Load libraries and set filepaths

suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(TxDb.Hsapiens.UCSC.hg38.knownGene))
suppressPackageStartupMessages(library(BSgenome.Hsapiens.UCSC.hg38))
suppressPackageStartupMessages(library(org.Hs.eg.db))
suppressPackageStartupMessages(library(VariantAnnotation))
db_path <- "./input"
output_dir <- "./output"
# ftp_path <- "ftp://ftp.ncbi.nlm.nih.gov/pub/clinvar/tab_delimited/variant_summary.txt.gz"

clinvar_EGFR_path <-
  file.path(db_path, "variant_summary_GRCh38_EGFR.tsv")

cosmic_path <-
  file.path(db_path, "Cosmic_GenomeScreensMutant_v99_GRCh38_EGFR.tsv")

ABE8e_path <-
  file.path(db_path, "sgrna_designs_ABE8e.csv")
BE4max_path <-
  file.path(db_path, "sgrna_designs_BE4max.csv")
syn_codon_path <-
  file.path(db_path, "syn_codons.txt")

variants_table_path <-
  file.path(output_dir, "variants_table.tsv")

all_variants_paired_path <-  
  file.path(output_dir, "all_variants_paired.tsv")

Extract clinvar data and save to file for later processing

# # run once
# clinvar_all_path <-
#   file.path(db_path, "variant_summary.txt.gz")
#
#
# clinvar_all <- read_tsv(gzfile(clinvar_all_path))
#
# clinvar_EGFR <-
#   clinvar_all %>%
#   filter(GeneSymbol == "EGFR" &
#     Assembly == "GRCh38" &
#     !(Type %in% c("Microsatellite", "Inversion")) &
#     Start >= 55019017)
# write_tsv(clinvar_EGFR, clinvar_EGFR_path)

Create Gene model for EGFR-201 (ENST00000275493.7)

hg_genome <- BSgenome.Hsapiens.UCSC.hg38
txdb <- TxDb.Hsapiens.UCSC.hg38.knownGene
txdb <- keepSeqlevels(txdb, "chr7")
tx_lengths <-
  transcriptLengths(txdb,
    with.utr5_len = TRUE,
    with.utr3_len = TRUE
  )

tx_lengths <-
  tx_lengths %>%
  dplyr::filter(gene_id == 1956) %>%
  arrange(-nexon)
tx_lengths
(tx_lengths$tx_len - (tx_lengths$utr5_len + tx_lengths$utr3_len)) / 3
 [1] 1211.0000 1158.0000 1092.0000  706.0000  629.0000  406.0000  721.6667  344.6667 1275.6667  567.0000  221.6667  802.3333  187.0000

Get the cds parts, the introns, the 3UTR, and the 5UTR and combine

cds_tx <- cdsBy(txdb, by = "tx", use.names = TRUE)
cds_tx <- cds_tx["ENST00000275493.7"]

intbytx <- intronsByTranscript(txdb, use.names = TRUE)
intbytx <- intbytx["ENST00000275493.7"]


five_utr <- fiveUTRsByTranscript(txdb, use.names = TRUE)$ENST00000275493.7
three_utr <- threeUTRsByTranscript(txdb, use.names = TRUE)$ENST00000275493.7
gene_model_gr <-
  c(five_utr, cds_tx$ENST00000275493.7, intbytx$ENST00000275493.7, three_utr)
gene_model_gr <- sort(gene_model_gr)
id_col <- mcols(gene_model_gr)$cds_id
id_col[1] <- "5utr_247279"
id_col[57] <- "3utr_247330"
id_col[seq(2, 56, 2)] <- paste0("cds", 1:28, "_", id_col[seq(2, 56, 2)])
id_col[seq(3, 55, 2)] <- paste0("intron", 1:27)
mcols(gene_model_gr) <- DataFrame(id = id_col)
cds_seqs <- extractTranscriptSeqs(hg_genome, as(gene_model_gr, "GRangesList"))
mcols(gene_model_gr)$seq <- cds_seqs
gene_model_gr
GRanges object with 57 ranges and 2 metadata columns:
       seqnames            ranges strand |           id                     seq
          <Rle>         <IRanges>  <Rle> |  <character>          <DNAStringSet>
   [1]     chr7 55019017-55019277      + |  5utr_247279 AGACGTCCGG...GGGAGCAGCG
   [2]     chr7 55019278-55019365      + |  cds1_101519 ATGCGACCCT...GAAAAGAAAG
   [3]     chr7 55019366-55142285      + |      intron1 GTAAGGGCGT...TTTCTTCCAG
   [4]     chr7 55142286-55142437      + |  cds2_101520 TTTGCCAAGG...CTTCTTAAAG
   [5]     chr7 55142438-55143304      + |      intron2 GTTGGTGACT...CTCTTCTTAG
   ...      ...               ...    ... .          ...                     ...
  [53]     chr7 55201783-55202516      + |     intron26 GTATGTATGA...CCTCCTGCAG
  [54]     chr7 55202517-55202625      + | cds27_101551 CTGCAAAGCT...CCAGTGCCTG
  [55]     chr7 55202626-55205255      + |     intron27 GTGAGTGGCT...CCACTTTCAG
  [56]     chr7 55205256-55205617      + | cds28_101553 AATACATAAA...TGGAGCATGA
  [57]     chr7 55205618-55211628      + |  3utr_247330 CCACGGAGGA...TTGTTAACAA
  -------
  seqinfo: 1 sequence from hg38 genome
loc_lens <-
  tibble(loc = mcols(gene_model_gr)$id, loc_len = width(gene_model_gr))
loc_lens
EGFR_seq <- extractTranscriptSeqs(hg_genome, cds_tx)
EGFR_seq
DNAStringSet object of length 1:
    width seq                                                                                                                                                                                              names               
[1]  3633 ATGCGACCCTCCGGGACGGCCGGGGCAGCGCTCCTGGCGCTGCTGGCTGCGCTCTGCCCGGCGAGTCGGGCTCTGGAGGAAAAGAAAGTTTGCCA...AGCCAAGCCAAATGGCATCTTTAAGGGCTCCACAGCTGAAAATGCAGAATACCTAAGGGTCGCGCCACAAAGCAGTGAATTTATTGGAGCATGA ENST00000275493.7
EGFR_aa <- translate(EGFR_seq)
EGFR_aa
AAStringSet object of length 1:
    width seq                                                                                                                                                                                              names               
[1]  1211 MRPSGTAGAALLALLAALCPASRALEEKKVCQGTSNKLTQLGTFEDHFLSLQRMFNNCEVVLGNLEITYVQRNYDLSFLKTIQEVAGYVLIALNT...APSRDPHYQDPHSTAVGNPEYLNTVQPTCVNSTFDSPAHWAQKGSHQISLDNPDYQQDFFPKEAKPNGIFKGSTAENAEYLRVAPQSSEFIGA* ENST00000275493.7
cds_starts <- start(cds_tx)
cds_ends <- end(cds_tx)
cds_width <-
  transcriptWidths(
    exonStarts = cds_starts,
    exonEnds = cds_ends
  )
ref_locs <- transcriptLocs2refLocs(list(c(1:cds_width)),
  exonStarts = cds_starts,
  exonEnds = cds_ends,
  strand = c("+")
)[[1]]
ref_locs[1:10]
 [1] 55019278 55019279 55019280 55019281 55019282 55019283 55019284 55019285 55019286 55019287

Load, combine, and filter variant data

Load clinvar data

clinvar_hg38_EGFR <-
  read_tsv(clinvar_EGFR_path)
Rows: 2444 Columns: 34── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (23): Type, Name, GeneSymbol, HGNC_ID, ClinicalSignificance, LastEvaluated, nsv/esv (dbVar), RCVaccession, PhenotypeIDS, PhenotypeList, Origin, OriginSimple, Assembly, ChromosomeAccession, ReferenceAllele, Alternate...
dbl (11): #AlleleID, GeneID, ClinSigSimple, RS# (dbSNP), Chromosome, Start, Stop, NumberSubmitters, SubmitterCategories, VariationID, PositionVCF
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
clinvar_hg38_EGFR <-
  clinvar_hg38_EGFR %>%
  dplyr::select(
    -GeneID, -GeneSymbol, -HGNC_ID, -`nsv/esv (dbVar)`,
    -Assembly, -ChromosomeAccession, -ReferenceAllele,
    -AlternateAllele, -Cytogenetic
  ) %>%
  mutate(var_len = pmax(
    str_length(ReferenceAlleleVCF),
    str_length(AlternateAlleleVCF)
  )) %>%
  filter(var_len <= 10) %>%
  arrange(PositionVCF)

# only keep main transcript variants
clinvar_hg38_EGFR <-
  clinvar_hg38_EGFR %>%
  filter(Name != "NM_001346941.2(EGFR):c.89-4536_89-4529del")
clinvar_hg38_EGFR
clinvar_hg38_EGFR_renamed <-
  clinvar_hg38_EGFR %>%
  dplyr::select(
    Name, Start, Stop,
    ReferenceAlleleVCF,
    AlternateAlleleVCF,
    VariationID
  ) %>%
  set_names(c(
    "name", "start", "stop",
    "ref", "alt", "clinvar_id"
  )) %>%
  mutate(name = str_replace(
    name, "NM_005228.5\\(EGFR\\):",
    paste0("g", start, "_")
  )) %>%
  mutate(clinvar_id = as.character(clinvar_id))
clinvar_hg38_EGFR_renamed
clinvar_hg38_EGFR_not_snv <-
  clinvar_hg38_EGFR_renamed %>%
  filter(!(str_length(ref) == 1 &
    str_length(alt) == 1)) %>%
  mutate(type = case_when(
    (str_length(ref) == str_length(alt) &
      str_length(ref) == 1) ~ "snv",
    (str_sub(ref, 1, 1) == alt &
      str_length(alt) < str_length(ref)) ~ "del",
    (str_sub(alt, 1, 1) == ref &
      str_length(ref) == 1 &
      str_length(alt) > 1) ~ "ins",
    TRUE ~ "indel"
  )) %>%
  mutate(stop = if_else(type == "ins", stop - 1, stop)) %>%
  mutate(
    alt = if_else(type == "del", "", alt),
    ref = if_else(type == "del", str_sub(ref, 2), ref)
  ) %>%
  rename(clinvar_id = "id") %>%
  relocate(type, .after = "name")
clinvar_hg38_EGFR_not_snv
clinvar_hg38_EGFR_snv <-
  clinvar_hg38_EGFR_renamed %>%
  filter((str_length(ref) == 1 & str_length(alt) == 1))
clinvar_hg38_EGFR_snv

Load COSMIC data

cosmic_dt <-
  read_tsv(cosmic_path)
Rows: 15654 Columns: 26── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (20): GENE_SYMBOL, COSMIC_GENE_ID, TRANSCRIPT_ACCESSION, COSMIC_SAMPLE_ID, SAMPLE_NAME, COSMIC_PHENOTYPE_ID, GENOMIC_MUTATION_ID, LEGACY_MUTATION_ID, MUTATION_CDS, MUTATION_AA, MUTATION_DESCRIPTION, MUTATION_ZYGOSIT...
dbl  (5): MUTATION_ID, CHROMOSOME, GENOME_START, GENOME_STOP, PUBMED_PMID
lgl  (1): LOH
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
cosmic_dt <-
  cosmic_dt %>%
  filter(TRANSCRIPT_ACCESSION == "ENST00000275493.6") %>%
  group_by(GENOMIC_MUTATION_ID) %>%
  dplyr::slice(1) %>%
  ungroup()

cosmic_dt_subset <-
  cosmic_dt %>%
  dplyr::select(
    MUTATION_CDS, MUTATION_AA,
    GENOME_START, GENOME_STOP,
    GENOMIC_WT_ALLELE, GENOMIC_MUT_ALLELE,
    GENOMIC_MUTATION_ID, MUTATION_DESCRIPTION
  ) %>%
  mutate(MUTATION_AA = str_replace(MUTATION_AA, "p.\\?", "")) %>%
  mutate(name = if_else(MUTATION_AA == "",
    paste0("g", GENOME_START, "_", MUTATION_CDS),
    paste0("g", GENOME_START, "_", MUTATION_CDS, " (", MUTATION_AA, ")")
  )) %>%
  dplyr::select(
    name, GENOME_START, GENOME_STOP,
    GENOMIC_WT_ALLELE, GENOMIC_MUT_ALLELE,
    GENOMIC_MUTATION_ID
  ) %>%
  set_names(c("name", "start", "stop", "ref", "alt", "cosmic_id")) %>%
  mutate(
    ref = if_else(is.na(ref), "", ref),
    alt = if_else(is.na(alt), "", alt)
  ) %>%
  mutate(var_len = pmax(str_length(ref), str_length(alt))) %>%
  filter(var_len <= 10) %>%
  dplyr::select(-var_len) %>%
  arrange(start)



cosmic_dt_subset_snv <-
  cosmic_dt_subset %>%
  filter(str_length(ref) == 1 & str_length(alt) == 1)

cosmic_dt_subset_not_snv <-
  cosmic_dt_subset %>%
  filter(!(str_length(ref) == 1 & str_length(alt) == 1))

cosmic_dt_subset_snv
cosmic_dt_subset_not_snv <-
  cosmic_dt_subset_not_snv %>%
  mutate(type = case_when(
    (str_length(ref) == str_length(alt) & str_length(ref) == 1) ~ "snv",
    (str_length(ref) >= 1 & str_length(alt) == 0) ~ "del",
    (str_length(ref) == 0 & str_length(alt) >= 1) ~ "ins",
    TRUE ~ "indel"
  )) %>%
  relocate(type, .after = name)


cosmic_dt_subset_not_snv <-
  cosmic_dt_subset_not_snv %>%
  mutate(extra_base = map_chr(
    cosmic_dt_subset_not_snv$start,
    ~ as.character(subseq(hg_genome[["chr7"]], ., .))
  )) %>%
  mutate(
    stop = if_else(type == "ins", stop - 1, stop),
    ref = if_else(type == "ins", extra_base, ref),
    alt = if_else(type == "ins", paste0(extra_base, alt), alt)
  ) %>%
  dplyr::select(-extra_base)
cosmic_dt_subset_not_snv
snv_dt <-
  full_join(cosmic_dt_subset_snv,
    clinvar_hg38_EGFR_snv,
    by = c("start", "stop", "ref", "alt")
  ) %>%
  mutate(name = if_else(is.na(name.x), name.y, name.x)) %>%
  dplyr::select(
    name, start, stop,
    ref, alt, cosmic_id,
    clinvar_id
  ) %>%
  arrange(start) %>%
  mutate(name = gsub("_c\\.\\d+[+-]?\\d+([[:alpha:]])>", "_\\1>", name))
snv_dt

Load variants from base editor experiments

ABE8e_all_dt <- read_csv(ABE8e_path)
New names:Rows: 834 Columns: 29── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): sgRNA.sequence, sgRNA.context.sequence, Gene.Symbol, Ensembl.Gene.ID, Ensembl.transcript.ID, Genome.assembly, Transcript.reference.allele, Transcript.alternate.allele, Genome.reference.allele, Genome.alternate...
dbl  (8): ...1, Gene.strand, Chromosome, sgrna.genomic.position, X..edits, X.silent.edits, Amino.acid.position_simplified, guide_codon_pos
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
BE4max_all_dt <- read_csv(BE4max_path)
New names:Rows: 834 Columns: 29── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): sgRNA.sequence, sgRNA.context.sequence, Gene.Symbol, Ensembl.Gene.ID, Ensembl.transcript.ID, Genome.assembly, Transcript.reference.allele, Transcript.alternate.allele, Genome.reference.allele, Genome.alternate...
dbl  (8): ...1, Gene.strand, Chromosome, sgrna.genomic.position, X..edits, X.silent.edits, Amino.acid.position_simplified, guide_codon_pos
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ABE8e_dt <- ABE8e_all_dt %>%
  dplyr::select(c(14, 15, 17, 20, 27))
BE4max_dt <- BE4max_all_dt %>%
  dplyr::select(c(14, 15, 17, 20, 27))
base_editor_variants <-
  bind_rows(BE4max_dt, ABE8e_dt) %>%
  dplyr::filter(Mutation.category_simplified %in%
    c("Nonsense", "Missense", "Splice-acceptor", "Splice-donor"))
base_editor_variants <-
  base_editor_variants %>%
  separate_rows(Nucleotide.edits, sep = "C_") %>%
  separate_rows(Nucleotide.edits, sep = "A_") %>%
  separate_rows(Nucleotide.edits, sep = "_") %>%
  separate_rows(Nucleotide.edits, sep = ";") %>%
  dplyr::filter(Nucleotide.edits != "") %>%
  mutate(Nucleotide.edits = as.integer(Nucleotide.edits)) %>%
  mutate(start = if_else(sgRNA.Strand == "sense",
    sgrna.genomic.position + (Nucleotide.edits - 1),
    sgrna.genomic.position - (Nucleotide.edits - 1)
  )) %>%
  mutate(
    edit =
      case_when(
        Edit == "C-T" & sgRNA.Strand == "antisense" ~ "G-A",
        Edit == "A-G" & sgRNA.Strand == "antisense" ~ "T-C",
        TRUE ~ Edit
      )
  ) %>%
  dplyr::select(start, edit) %>%
  group_by(start) %>%
  dplyr::slice(1) %>%
  tidyr::separate(edit,
    into = c("ref", "alt"), sep = "-"
  ) %>%
  mutate(
    stop = start,
    name = paste0("g", start, "_", ref, ">", alt)
  ) %>%
  dplyr::select(c("name", "start", "stop", "ref", "alt"))
base_editor_variants

Combine variants data

snv_dt <-
  full_join(snv_dt,
    base_editor_variants,
    by = c("start", "stop", "ref", "alt")
  )

snv_dt <-
  snv_dt %>%
  mutate(name = if_else(is.na(name.x), name.y, name.x)) %>%
  rename(name.y = "be_id") %>%
  dplyr::select(
    name, start, stop, ref,
    alt, cosmic_id, clinvar_id, be_id
  ) %>%
  unite("id", cosmic_id:be_id, sep = ";", na.rm = TRUE) %>%
  arrange(start) %>%
  mutate(type = "snv")
snv_dt
non_snv_dt <-
  full_join(clinvar_hg38_EGFR_not_snv,
    cosmic_dt_subset_not_snv,
    by = c("start", "stop", "ref", "alt", "type")
  ) %>%
  mutate(name = if_else(is.na(name.x), name.y, name.x)) %>%
  dplyr::select(
    name, type, start, stop,
    ref, alt, cosmic_id,
    id
  ) %>%
  arrange(start) %>%
  unite("id", cosmic_id:id, sep = ";", na.rm = TRUE)
non_snv_dt
variants_dt <-
  bind_rows(
    snv_dt,
    non_snv_dt
  ) %>%
  arrange(start) %>%
  mutate(name = sub(" \\(p\\..*$", "", name))

variants_dt

Annotate Variants

annotate_and_predict_variants <- function(variants_dt) {
  seq_len_min <- 49

  num_variants <- NROW(variants_dt)
  gr0 <-
    GRanges(
      Rle(c("chr7"), num_variants),
      IRanges(
        start = variants_dt$start,
        end = variants_dt$stop,
        names = variants_dt$name
      )
    )

  var_allelles <- DNAStringSet(variants_dt$alt)

  intron_locations <-
    locateVariants(gr0,
      intbytx,
      IntronVariants(),
      varAllele = var_allelles
    )
  # Locate intronic variants
  intron_locations <-
    intron_locations %>%
    as_tibble() %>%
    add_column(name = names(intron_locations)) %>%
    relocate(name, .before = "seqnames") %>%
    dplyr::select(-PRECEDEID, -FOLLOWID, -TXID)

  # Locate remaining variants
  all <- locateVariants(gr0,
    txdb,
    AllVariants(),
    varAllele = var_allelles
  )
  all <-
    all %>%
    as_tibble() %>%
    add_column(name = names(all)) %>%
    relocate(name, .before = "seqnames") %>%
    dplyr::select(-PRECEDEID, -FOLLOWID)

  # Flag intronic and 5UTR variants that have alternative 
  # effects given other potential spliced transcripts

  transcript_splice_sites <-
    all %>%
    dplyr::filter(LOCATION == "spliceSite" & TXID == "93502")

  intron_locations <-
    intron_locations %>%
    filter(!(name %in% transcript_splice_sites$name))

  uncertain_introns <-
    all %>%
    dplyr::filter(name %in% intron_locations$name) %>%
    group_by(name, LOCATION) %>%
    dplyr::slice(1) %>%
    ungroup() %>%
    group_by(name) %>%
    mutate(frac_intron = sum(LOCATION == "intron") / n()) %>%
    dplyr::filter(frac_intron < 1) %>%
    dplyr::filter(LOCATION != "intron") %>%
    dplyr::filter(TXID != 93502) %>%
    arrange(QUERYID) %>%
    dplyr::select(-GENEID, -frac_intron) %>%
    ungroup()

  flag_variants <-
    uncertain_introns %>%
    dplyr::select(name, LOCATION, TXID) %>%
    left_join(., tx_lengths %>%
      dplyr::select(tx_id, tx_name) %>%
      mutate(tx_id = as.character(tx_id)) %>%
      dplyr::rename(TXID = "tx_id"),
    by = "TXID"
    ) %>%
    dplyr::select(-TXID) %>%
    unite("alt_effect", LOCATION:tx_name)


  all <-
    all %>%
    dplyr::filter(TXID == 93502) %>%
    dplyr::select(-TXID)

  potential_promoters <-
    all[which(duplicated(all$name)), ] %>%
    dplyr::select(name) %>%
    mutate(alt_effect = "promoter_ENST00000275493.7")

  flag_variants <-
    bind_rows(flag_variants, potential_promoters)

  flag_variants <-
    flag_variants %>%
    group_by(name) %>%
    dplyr::slice(1) %>%
    ungroup()


  all <-
    all %>%
    dplyr::filter(!duplicated(all$name))


  all <-
    bind_rows(
      all,
      intron_locations
    )

  all <-
    left_join(all, flag_variants, by = "name") %>%
    dplyr::select(-GENEID)


  all <-
    all %>%
    dplyr::select(-c(LOCSTART:CDSID))

  gene_model_gr_list <-
    as(gene_model_gr, "GRangesList")

  names(gene_model_gr_list) <- mcols(gene_model_gr)$id

  map_grs <-
    mapToTranscripts(resize(gr0, 1), gene_model_gr_list)

  map_dt <-
    map_grs %>%
    as_tibble() %>%
    mutate(name = names(map_grs)) %>%
    dplyr::select(name, seqnames, start) %>%
    set_names(c("name", "loc", "loc_start")) %>%
    left_join(., loc_lens, by = "loc")

  all <-
    left_join(all,
      map_dt,
      by = "name"
    )

  # Predict consequence of variant
  predict_coding_variants <-
    predictCoding(gr0, txdb, hg_genome, varAllele = var_allelles)
  predict_coding_variants <-
    predict_coding_variants[mcols(predict_coding_variants)$TXID == 93502]
  predict_coding_variants <-
    as_tibble(predict_coding_variants) %>%
    add_column(name = names(predict_coding_variants)) %>%
    dplyr::select(
      name, CDSLOC.start, CONSEQUENCE, REFCODON,
      VARCODON, REFAA, VARAA, PROTEINLOC
    )

  n_distinct(all$name)

  all <-
    left_join(all, predict_coding_variants, by = "name")



  all <-
    all %>%
    mutate(loc_end_comp = loc_len - (loc_start + width - 1)) %>%
    mutate(boundary_flag = (LOCATION == "coding" &
      (loc_start < seq_len_min | loc_end_comp < seq_len_min)))

  all <-
    all %>%
    dplyr::select(
      name, CONSEQUENCE, LOCATION, loc, loc_len, loc_start,
      CDSLOC.start, PROTEINLOC, REFCODON, VARCODON,
      REFAA, VARAA, boundary_flag, alt_effect
    ) %>%
    set_names(c(
      "name", "consequence", "location", "region", "region_len",
      "pos_region", "pos_cds", "pos_protein", "ref_codon",
      "var_codon", "ref_aa", "var_aa", "boundary_flag", "alt_effect"
    )) %>%
    rowwise() %>%
    mutate(pos_protein = str_c(pos_protein, collapse = ":"))

  return(all)
}
all <-
  annotate_and_predict_variants(variants_dt)
Warning: GRanges object contains 20914 out-of-bound ranges located on sequences 93501, 93502, 93503, 93504, 93505, 93509, and 93510. Note that ranges located on a sequence whose length is unknown (NA) or on a
  circular sequence are not considered out-of-bound (use seqlengths() and isCircular() to get the lengths and circularity flags of the underlying sequences). You can use trim() to trim these ranges.
  See ?`trim,GenomicRanges-method` for more information.'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
Warning: GRanges object contains 20914 out-of-bound ranges located on sequences 93501, 93502, 93503, 93504, 93505, 93509, and 93510. Note that ranges located on a sequence whose length is unknown (NA) or on a
  circular sequence are not considered out-of-bound (use seqlengths() and isCircular() to get the lengths and circularity flags of the underlying sequences). You can use trim() to trim these ranges.
  See ?`trim,GenomicRanges-method` for more information.Warning: records with missing 'varAllele' were ignoredWarning: in 'x[[12817]]': last 2 bases were ignoredWarning: in 'x[[12817]]': last 2 bases were ignored

Include base editing variants generated by two or more edits

min_base_changes <- function(target_amino_acid, ref_codon) {
  # Define a mapping of amino acids to codons
  amino_acid_mapping <- list(
    "A" = c("GCT", "GCC", "GCA", "GCG"),
    "R" = c("CGT", "CGC", "CGA", "CGG", "AGA", "AGG"),
    "N" = c("AAT", "AAC"),
    "D" = c("GAT", "GAC"),
    "C" = c("TGT", "TGC"),
    "Q" = c("CAA", "CAG"),
    "E" = c("GAA", "GAG"),
    "G" = c("GGT", "GGC", "GGA", "GGG"),
    "H" = c("CAT", "CAC"),
    "I" = c("ATA"), # "ATT", "ATC", two A>Ts
    "L" = c("TTA", "TTG", "CTT", "CTC", "CTA", "CTG"),
    "K" = c("AAA", "AAG"),
    "M" = c("ATG"),
    "F" = c("TTT", "TTC"),
    "P" = c("CCT", "CCC", "CCA", "CCG"),
    "S" = c("TCT", "TCC", "TCA", "TCG", "AGT", "AGC"),
    "T" = c("ACT", "ACC", "ACA", "ACG"),
    "W" = c("TGG"),
    "Y" = c("TAT", "TAC"),
    "V" = c("GTT", "GTC", "GTA", "GTG"),
    "*" = c("TAA", "TAG", "TGA")
  )

  # Find the reference amino acid corresponding to the reference codon
  ref_amino_acid <-
    names(amino_acid_mapping)[which(ref_codon %in% unlist(amino_acid_mapping))]

  # Check if the reference amino acid is valid
  if (is.null(ref_amino_acid)) {
    stop("Invalid reference codon.")
  }

  # Check if the target amino acid is valid
  if (!(target_amino_acid %in% names(amino_acid_mapping))) {
    stop("Invalid target amino acid.")
  }

  # Find the target codons for the given amino acid
  target_codons <- amino_acid_mapping[[target_amino_acid]]

  # Calculate the number of base changes needed for each target codon
  base_changes <-
    sapply(
      target_codons,
      function(tc) sum(strsplit(ref_codon, "")[[1]] != strsplit(tc, "")[[1]])
    )

  # Find the index of the minimum base changes
  min_index <-
    which.min(base_changes)

  # Return the variant codon with minimum base changes
  return(target_codons[min_index])
}

get_codon_at_aa_position <- function(pos) {
  start_pos <- pos * 3 - 2
  end_pos <- pos * 3
  as.character(subseq(EGFR_seq, start_pos, end_pos))
}


ABE8e_aa_var <-
  ABE8e_all_dt %>%
  dplyr::select(Amino.acid.edits) %>%
  separate_rows(Amino.acid.edits, sep = ";") %>%
  dplyr::filter(!(Amino.acid.edits %in% c("utr", "None", ""))) %>%
  dplyr::filter(!str_detect(Amino.acid.edits, "Exon")) %>%
  separate_wider_regex(Amino.acid.edits,
    c(
      ref_aa = "^[A-Za-z]+",
      pos_protein = "[0-9]+",
      var_aa = "[A-Za-z]+$"
    ),
    cols_remove = F
  ) %>%
  dplyr::filter(ref_aa != var_aa)


BE4max_aa_var <-
  BE4max_all_dt %>%
  dplyr::select(Amino.acid.edits) %>%
  separate_rows(Amino.acid.edits, sep = ";") %>%
  dplyr::filter(!(Amino.acid.edits %in% c("utr", "None", ""))) %>%
  dplyr::filter(!str_detect(Amino.acid.edits, "Exon")) %>%
  separate_wider_regex(Amino.acid.edits,
    c(
      ref_aa = "^[A-Za-z]+",
      pos_protein = "[0-9]+",
      var_aa = "[A-Za-z]+$"
    ),
    cols_remove = F
  ) %>%
  dplyr::filter(ref_aa != var_aa)

aa_map <- c(AMINO_ACID_CODE, "*" = "Ter")
flipped_aa_map <- setNames(names(aa_map), aa_map)

be_var_dt <-
  bind_rows(ABE8e_aa_var, BE4max_aa_var) %>%
  group_by(Amino.acid.edits) %>%
  dplyr::slice(1) %>%
  ungroup() %>%
  mutate(
    ref_aa = flipped_aa_map[ref_aa],
    var_aa = flipped_aa_map[var_aa]
  )

variants_dt0 <-
  left_join(variants_dt, all, by = "name")

be_var_dt <-
  left_join(be_var_dt,
    variants_dt0 %>%
      filter(pos_protein != "" & type == "snv") %>%
      dplyr::select(name, ref_aa, pos_protein, var_aa),
    by = c("ref_aa", "pos_protein", "var_aa")
  ) %>%
  dplyr::filter(is.na(name)) %>%
  mutate(pos_protein = as.numeric(pos_protein)) %>%
  rowwise() %>%
  mutate(ref_codon = get_codon_at_aa_position(pos_protein))

be_var_dt <-
  be_var_dt %>%
  mutate(var_codon = min_base_changes(var_aa, ref_codon))

be_var_dt <-
  be_var_dt %>%
  mutate(
    last_base_diff =
      str_sub(ref_codon, 3, 3) != str_sub(var_codon, 3, 3)
  ) %>%
  mutate(
    ref = if_else(last_base_diff, ref_codon, str_sub(ref_codon, 1, 2)),
    alt = if_else(last_base_diff, var_codon, str_sub(var_codon, 1, 2)),
    start = ref_locs[pos_protein * 3 - 2],
    stop = if_else(last_base_diff, start + 2, start + 1)
  ) %>%
  mutate(name = paste0("g", start, "_", ref, ">", alt)) %>%
  mutate(
    id = name,
    type = "indel"
  ) %>%
  dplyr::select(c("name", "type", "start", "stop", "ref", "alt", "id"))
rm(variants_dt0)

# remove g55174776_TT>CC since it is the same as g55174776_c.2239_2240delinsCC
be_var_dt <-
  be_var_dt %>%
  filter(name != "g55174776_TT>CC")
be_var_dt

Include double base edits variants

variants_dt <-
  bind_rows(variants_dt, be_var_dt) %>%
  arrange(start)

Reannotate after inclusion of double base edits variants

all <-
  annotate_and_predict_variants(variants_dt)
Warning: GRanges object contains 21739 out-of-bound ranges located on sequences 93501, 93502, 93503, 93504, 93505, 93509, and 93510. Note that ranges located on a sequence whose length is unknown (NA) or on a
  circular sequence are not considered out-of-bound (use seqlengths() and isCircular() to get the lengths and circularity flags of the underlying sequences). You can use trim() to trim these ranges.
  See ?`trim,GenomicRanges-method` for more information.'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
'select()' returned many:1 mapping between keys and columns
Warning: GRanges object contains 21739 out-of-bound ranges located on sequences 93501, 93502, 93503, 93504, 93505, 93509, and 93510. Note that ranges located on a sequence whose length is unknown (NA) or on a
  circular sequence are not considered out-of-bound (use seqlengths() and isCircular() to get the lengths and circularity flags of the underlying sequences). You can use trim() to trim these ranges.
  See ?`trim,GenomicRanges-method` for more information.Warning: records with missing 'varAllele' were ignoredWarning: in 'x[[13259]]': last 2 bases were ignoredWarning: in 'x[[13259]]': last 2 bases were ignored
variants_dt <-
  left_join(variants_dt, all, by = "name")

variants_dt
table(variants_dt$location)

spliceSite     intron    fiveUTR   threeUTR     coding intergenic   promoter 
        65       1825          5         61       3060          0          0 
table(variants_dt$location, variants_dt$type)
            
              del indel  ins  snv
  spliceSite    1     0    2   62
  intron       66     3   38 1718
  fiveUTR       0     0    0    5
  threeUTR      5     0    3   53
  coding       27   127   35 2871
  intergenic    0     0    0    0
  promoter      0     0    0    0

Filter out introns

variants_dt <-
  variants_dt %>%
  filter(location != c("intron"))
variants_dt

Generate synonymous mutations near target Single Nucleotide Variants

# Function to split a string into consecutive triplets
split_into_triplets <- function(s) {
  n <- nchar(s)
  if (n %% 3 != 0) {
    warning("String length is not a multiple of 3. Padding with spaces.")
    s <- paste0(s, rep(" ", 3 - (n %% 3)))
  }
  matrix(strsplit(s, "")[[1]], ncol = 3, byrow = TRUE)
}

# Split the vector into triplets
triplets <- split_into_triplets(as.character(EGFR_seq))

# Create a dataframe
codon_map_df <-
  tibble(ref_codon = apply(triplets, 1, paste, collapse = "")) %>%
  mutate(pos_protein = row_number())
codon_map_df
syn_codon_map <-
  read_delim(syn_codon_path)
Rows: 59 Columns: 5── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: " "
chr (5): ref_aa, ref_codon, var_codon, ref, alt
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
syn_codon_map
codon_map_df <-
  left_join(codon_map_df, syn_codon_map, by = "ref_codon") %>%
  mutate(start = ref_locs[pos_protein * 3]) %>%
  filter(!is.na(ref_aa))
codon_map_df

Split SNVS into spliceSite coding, and intron variants

variants_snv <-
  variants_dt %>%
  filter(type == "snv")

variants_snv_coding <-
  variants_snv %>%
  filter(location %in% c("coding"))

Find nonsynomous mutations

get_codon_map <- function(start, name, num_idx) {
  dis <- abs(start - codon_map_df$start)
  dis[dis <= 2] <- 10000
  lowest_indices <- head(order(dis), num_idx)

  bp_dist <- codon_map_df$start[lowest_indices] - start

  dt <- tibble(name = name, dist = bp_dist)
  dt <- bind_cols(dt, codon_map_df[lowest_indices, ])
  return(dt)
}

coding_syn <-
  map2_df(variants_snv_coding$start,
    variants_snv_coding$name,
    get_codon_map,
    num_idx = 1
  ) %>%
  rename(name = "target_name") %>%
  mutate(name = paste0("g", start, "_", ref, ">", alt)) %>%
  dplyr::select(
    name, start, ref, alt, ref,
    target_name, pos_protein,
    ref_codon, var_codon, ref_aa, dist
  )
table(coding_syn$dist)

 -8  -7  -6  -5  -4  -3   3   4   5   6   7   8 
  1   4   4  54 910 955  38 845  53   1   4   2 
coding_syn <-
  coding_syn %>%
  dplyr::select(-dist) %>%
  group_by(name) %>%
  mutate(target_name = paste(target_name, collapse = ";")) %>%
  dplyr::slice(1)
coding_syn
## Previous code for including intronic variants!!

# variants_snv_intron <-
#   variants_snv %>%
#   filter(location %in% c("intron", "spliceSite"))

# mut_pos_dist <- 3
# intron_syn <-
#   variants_snv_intron %>%
#   dplyr::select(name, start, region_len, pos_region) %>%
#   mutate(pos_region_comp = region_len - pos_region) %>%
#   mutate(upstream = case_when(
#     pos_region_comp < 8 ~ F,
#     pos_region_comp >= 8 ~ T
#   )) %>%
#   mutate(
#     start_syn = if_else(upstream, start + mut_pos_dist, start - mut_pos_dist),
#     ref = map_chr(
#       start_syn,
#       ~ as.character(subseq(hg_genome[["chr7"]], ., .))
#     )
#   )
#

# dup_alternatives <-
#   intron_syn %>%
#   filter(start %in% intron_syn$start_syn) %>%
#   separate(name, into = c("edit", "alt0"), remove = F, sep = ">") %>%
#   separate(edit, into = c("loc", "ref0"), remove = F, sep = "_") %>%
#   dplyr::select(name, start, ref0, alt0) %>%
#   group_by(start) %>%
#   mutate(bases = paste(alt0, collapse = ",")) %>%
#   ungroup() %>%
#   mutate(bases = paste0(bases, ",", ref0)) %>%
#   rowwise() %>%
#   mutate(alt_2 = setdiff(c("A", "C", "T", "G"),
#                          str_split(bases, pattern = ",")[[1]])[1]) %>%
#   mutate(name_sym = paste0("g", start, "_", ref0, ">", alt_2)) %>%
#   dplyr::select(name, name_sym, alt_2)
# dup_alternatives

# intron_syn <-
#   intron_syn %>%
#   mutate(alt = case_when(
#     ref == "G" ~ "A",
#     ref == "A" ~ "G",
#     ref == "C" ~ "T",
#     ref == "T" ~ "C"
#   )) %>%
#   dplyr::select(name, start_syn, ref, alt) %>%
#   dplyr::rename(target_name = "name", start = "start_syn") %>%
#   mutate(name = paste0("g", start, "_", ref, ">", alt)) %>%
#   dplyr::select(name, start, ref, alt, target_name) %>%
#   group_by(name) %>%
#   mutate(target_name = paste(target_name, collapse = ";")) %>%
#   dplyr::slice(1)


# intron_syn <-
#   left_join(intron_syn,
#     dup_alternatives,
#     by = "name"
#   ) %>%
#   mutate(
#     name = if_else(is.na(name_sym), name, name_sym),
#     alt = if_else(is.na(alt_2), alt, alt_2)
#   ) %>%
#   dplyr::select(-name_sym, -alt_2)

# syn_variants <-
#   bind_rows(
#     coding_syn %>%
#       mutate(location = "coding"),
#     intron_syn %>%
#       mutate(
#         pos_protein = NA,
#         ref_codon = NA,
#         var_codon = NA,
#         ref_aa = NA,
#         location = "intron"
#       )
#   )
# syn_variants
syn_variants <-
  left_join(
    coding_syn %>%
      mutate(location = "coding"),
    variants_snv %>%
      dplyr::select(name, id),
    by = "name"
  ) %>%
  mutate(
    syn_in_target = name %in% variants_dt$name,
    num_targets = str_count(target_name, ";") + 1
  )
syn_variants
syn_target_map <-
  syn_variants %>%
  group_by(num_targets, syn_in_target) %>%
  tally()
syn_target_map
syn_variants_long <-
  syn_variants %>%
  separate_rows(target_name, sep = ";") %>%
  dplyr::select(
    target_name, name, start, ref,
    alt
  ) %>%
  set_names(c(
    "name", "name_syn", "start_syn",
    "ref_syn", "alt_syn"
  ))
syn_variants_long
variants_dt <-
  left_join(variants_dt, syn_variants_long, by = "name")
variants_dt
variants_dt <-
  variants_dt %>%
  mutate(target_in_syn = if_else(name %in% syn_variants$name, T, F)) %>%
  mutate(name_target_syn = paste0(name, ":", name_syn)) %>%
  mutate(
    clinvar = if_else(grepl("\\b\\d+\\b", id), T, F),
    cosmic = if_else(grepl("COSV", id), T, F),
    base_edit = if_else(grepl("g\\d+_[A-Z]+>[A-Z]+", id), T, F)
  ) %>%
  dplyr::select(
    name, id, ref, alt, ref_aa, var_aa, pos_protein,
    type, consequence, location, name_syn, name_target_syn,
    target_in_syn, alt_effect,
    clinvar, cosmic, base_edit, start, stop, start_syn, everything()
  )  %>%
  mutate(name_target_syn=if_else(is.na(name_syn), NA, name_target_syn)) 
variants_dt

Split variants into target, target_syn, and syn

variants_snv <-
  variants_dt %>%
  filter(!is.na(name_syn))  


target_syn_variants <-
  variants_snv  %>%
  dplyr::select(name_target_syn, name_syn, name) %>%
  set_names(c("target_name","name_syn", "name_target"))  %>%
  mutate( name_target_syn=NA,
          num_targets=NA,
          paired_targets_as_syn= NA, 
          paired_targets_syn_as_syn= NA) %>%
  dplyr::select(target_name, name_target, name_syn, 
                name_target_syn,
                num_targets, paired_targets_as_syn,
                paired_targets_syn_as_syn )
target_syn_variants
NA
syn_variants_dt <-
  variants_snv %>%
  dplyr::select(name_syn, name, name_target_syn) %>%
  set_names(c("target_name", "name_target", "name_target_syn" ))  %>%

  group_by(target_name)%>% 
  mutate(name_target = paste(name_target, collapse = ";"),
         name_target_syn = paste(name_target_syn, collapse = ";")) %>% 
  dplyr::slice(1)    %>% 
  mutate( 
          syn_in_target = target_name %in% variants_dt$name,
          num_targets = str_count(name_target, ";") + 1
  )


syn_variants_dt_filtered <-
  syn_variants_dt %>%
  mutate(target_in_syn=NA,
        name_syn=NA,
        paired_targets_as_syn= NA, 
        paired_targets_syn_as_syn= NA) %>%
  filter(!(syn_in_target))%>%
  dplyr::select(target_name, name_target, name_syn,
                name_target_syn,
                num_targets, 
                paired_targets_as_syn, 
                paired_targets_syn_as_syn )

syn_variants_in_target <-
    syn_variants_dt %>%
  filter((syn_in_target)) %>%
  dplyr::select(-syn_in_target) %>%
  rename(name_target="paired_targets_as_syn",
         name_target_syn="paired_targets_syn_as_syn")
syn_variants_dt_filtered
variants_dt <-
  left_join(variants_dt, 
          syn_variants_in_target %>%
  rename(target_name="name"),
  by="name")
variants_dt
target_variants <-
  variants_dt %>%
  dplyr::select(name, name_syn, name_target_syn, paired_targets_as_syn, paired_targets_syn_as_syn, num_targets) %>%
  set_names(c("target_name", "name_syn", "name_target_syn", "paired_targets_as_syn", "paired_targets_syn_as_syn", "num_targets"))  %>%
  mutate(name_target=NA)  %>%
  dplyr::select(target_name, name_target, name_syn,
                name_target_syn,
                num_targets, 
                paired_targets_as_syn, 
                paired_targets_syn_as_syn )
  
target_variants
all_variants_paired <- 
  bind_rows(target_variants, 
            target_syn_variants, 
            syn_variants_dt_filtered)
all_variants_paired 

Save to files

write_tsv(
  all_variants_paired,
  all_variants_paired_path
)

write_tsv(
  variants_dt, variants_table_path)
sessionInfo()
R version 4.3.2 (2023-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.6 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0 
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Zurich
tzcode source: system (glibc)

attached base packages:
[1] stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] VariantAnnotation_1.48.1                 Rsamtools_2.18.0                         SummarizedExperiment_1.32.0              MatrixGenerics_1.14.0                    matrixStats_1.2.0                       
 [6] org.Hs.eg.db_3.18.0                      BSgenome.Hsapiens.UCSC.hg38_1.4.5        BSgenome_1.70.1                          rtracklayer_1.62.0                       BiocIO_1.12.0                           
[11] Biostrings_2.70.1                        XVector_0.42.0                           TxDb.Hsapiens.UCSC.hg38.knownGene_3.18.0 GenomicFeatures_1.54.1                   AnnotationDbi_1.64.1                    
[16] Biobase_2.62.0                           GenomicRanges_1.54.1                     GenomeInfoDb_1.38.5                      IRanges_2.36.0                           S4Vectors_0.40.2                        
[21] BiocGenerics_0.48.1                      lubridate_1.9.3                          forcats_1.0.0                            stringr_1.5.1                            dplyr_1.1.4                             
[26] purrr_1.0.2                              readr_2.1.5                              tidyr_1.3.0                              tibble_3.2.1                             ggplot2_3.4.4                           
[31] tidyverse_2.0.0                         

loaded via a namespace (and not attached):
 [1] tidyselect_1.2.0         blob_1.2.4               filelock_1.0.3           bitops_1.0-7             fastmap_1.1.1            RCurl_1.98-1.14          BiocFileCache_2.10.1     GenomicAlignments_1.38.1
 [9] XML_3.99-0.16            digest_0.6.34            timechange_0.2.0         lifecycle_1.0.4          KEGGREST_1.42.0          RSQLite_2.3.4            magrittr_2.0.3           compiler_4.3.2          
[17] rlang_1.1.3              progress_1.2.3           tools_4.3.2              utf8_1.2.4               yaml_2.3.8               knitr_1.45               S4Arrays_1.2.0           prettyunits_1.2.0       
[25] bit_4.0.5                curl_5.2.0               DelayedArray_0.28.0      xml2_1.3.6               abind_1.4-5              BiocParallel_1.36.0      withr_2.5.2              grid_4.3.2              
[33] fansi_1.0.6              colorspace_2.1-0         scales_1.3.0             biomaRt_2.58.0           cli_3.6.2                crayon_1.5.2             generics_0.1.3           rstudioapi_0.15.0       
[41] httr_1.4.7               tzdb_0.4.0               rjson_0.2.21             DBI_1.2.1                cachem_1.0.8             zlibbioc_1.48.0          parallel_4.3.2           restfulr_0.0.15         
[49] vctrs_0.6.5              Matrix_1.6-5             hms_1.1.3                bit64_4.0.5              glue_1.7.0               codetools_0.2-19         stringi_1.8.3            gtable_0.3.4            
[57] munsell_0.5.0            pillar_1.9.0             rappdirs_0.3.3           GenomeInfoDbData_1.2.11  R6_2.5.1                 dbplyr_2.4.0             vroom_1.6.5              lattice_0.22-5          
[65] png_0.1-8                memoise_2.0.1            SparseArray_1.2.3        xfun_0.41                pkgconfig_2.0.3         
LS0tCnRpdGxlOiAiRUdGUiBQcmltZSBFZGl0aW5nIExpYnJhcnkiCnN1YnRpdGxlOiAiUGFydCAxOiBDb21iaW5lIFZhcmlhbnRzIGFuZCBDcmVhdGUgVGFibGUiCmF1dGhvcjogCi0gbmFtZTogUmljayBGYXJvdW5pCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVZLSVCLSVkIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICB0b2M6IG5vCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKCgojIExvYWQgbGlicmFyaWVzIGFuZCBzZXQgZmlsZXBhdGhzIAoKCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShUeERiLkhzYXBpZW5zLlVDU0MuaGczOC5rbm93bkdlbmUpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShCU2dlbm9tZS5Ic2FwaWVucy5VQ1NDLmhnMzgpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShvcmcuSHMuZWcuZGIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShWYXJpYW50QW5ub3RhdGlvbikpCmBgYAoKCmBgYHtyfQpkYl9wYXRoIDwtICIuL2lucHV0IgpvdXRwdXRfZGlyIDwtICIuL291dHB1dCIKIyBmdHBfcGF0aCA8LSAiZnRwOi8vZnRwLm5jYmkubmxtLm5paC5nb3YvcHViL2NsaW52YXIvdGFiX2RlbGltaXRlZC92YXJpYW50X3N1bW1hcnkudHh0Lmd6IgoKY2xpbnZhcl9FR0ZSX3BhdGggPC0KICBmaWxlLnBhdGgoZGJfcGF0aCwgInZhcmlhbnRfc3VtbWFyeV9HUkNoMzhfRUdGUi50c3YiKQoKY29zbWljX3BhdGggPC0KICBmaWxlLnBhdGgoZGJfcGF0aCwgIkNvc21pY19HZW5vbWVTY3JlZW5zTXV0YW50X3Y5OV9HUkNoMzhfRUdGUi50c3YiKQoKQUJFOGVfcGF0aCA8LQogIGZpbGUucGF0aChkYl9wYXRoLCAic2dybmFfZGVzaWduc19BQkU4ZS5jc3YiKQpCRTRtYXhfcGF0aCA8LQogIGZpbGUucGF0aChkYl9wYXRoLCAic2dybmFfZGVzaWduc19CRTRtYXguY3N2IikKc3luX2NvZG9uX3BhdGggPC0KICBmaWxlLnBhdGgoZGJfcGF0aCwgInN5bl9jb2RvbnMudHh0IikKCnZhcmlhbnRzX3RhYmxlX3BhdGggPC0KICBmaWxlLnBhdGgob3V0cHV0X2RpciwgInZhcmlhbnRzX3RhYmxlLnRzdiIpCgphbGxfdmFyaWFudHNfcGFpcmVkX3BhdGggPC0gIAogIGZpbGUucGF0aChvdXRwdXRfZGlyLCAiYWxsX3ZhcmlhbnRzX3BhaXJlZC50c3YiKQpgYGAKCiMjIEV4dHJhY3QgY2xpbnZhciBkYXRhIGFuZCBzYXZlIHRvIGZpbGUgZm9yIGxhdGVyIHByb2Nlc3NpbmcKCmBgYHtyfQojICMgcnVuIG9uY2UKIyBjbGludmFyX2FsbF9wYXRoIDwtCiMgICBmaWxlLnBhdGgoZGJfcGF0aCwgInZhcmlhbnRfc3VtbWFyeS50eHQuZ3oiKQojCiMKIyBjbGludmFyX2FsbCA8LSByZWFkX3RzdihnemZpbGUoY2xpbnZhcl9hbGxfcGF0aCkpCiMKIyBjbGludmFyX0VHRlIgPC0KIyAgIGNsaW52YXJfYWxsICU+JQojICAgZmlsdGVyKEdlbmVTeW1ib2wgPT0gIkVHRlIiICYKIyAgICAgQXNzZW1ibHkgPT0gIkdSQ2gzOCIgJgojICAgICAhKFR5cGUgJWluJSBjKCJNaWNyb3NhdGVsbGl0ZSIsICJJbnZlcnNpb24iKSkgJgojICAgICBTdGFydCA+PSA1NTAxOTAxNykKIyB3cml0ZV90c3YoY2xpbnZhcl9FR0ZSLCBjbGludmFyX0VHRlJfcGF0aCkKYGBgCgojIENyZWF0ZSBHZW5lIG1vZGVsIGZvciBFR0ZSLTIwMSAoRU5TVDAwMDAwMjc1NDkzLjcpCgpgYGB7cn0KaGdfZ2Vub21lIDwtIEJTZ2Vub21lLkhzYXBpZW5zLlVDU0MuaGczOApgYGAKCmBgYHtyfQp0eGRiIDwtIFR4RGIuSHNhcGllbnMuVUNTQy5oZzM4Lmtub3duR2VuZQp0eGRiIDwtIGtlZXBTZXFsZXZlbHModHhkYiwgImNocjciKQpgYGAKCgoKYGBge3J9CnR4X2xlbmd0aHMgPC0KICB0cmFuc2NyaXB0TGVuZ3Rocyh0eGRiLAogICAgd2l0aC51dHI1X2xlbiA9IFRSVUUsCiAgICB3aXRoLnV0cjNfbGVuID0gVFJVRQogICkKCnR4X2xlbmd0aHMgPC0KICB0eF9sZW5ndGhzICU+JQogIGRwbHlyOjpmaWx0ZXIoZ2VuZV9pZCA9PSAxOTU2KSAlPiUKICBhcnJhbmdlKC1uZXhvbikKdHhfbGVuZ3RocwpgYGAKCgpgYGB7cn0KKHR4X2xlbmd0aHMkdHhfbGVuIC0gKHR4X2xlbmd0aHMkdXRyNV9sZW4gKyB0eF9sZW5ndGhzJHV0cjNfbGVuKSkgLyAzCmBgYAoKIyMjIEdldCB0aGUgY2RzIHBhcnRzLCB0aGUgaW50cm9ucywgdGhlIDNVVFIsIGFuZCB0aGUgNVVUUiBhbmQgY29tYmluZQoKCmBgYHtyfQpjZHNfdHggPC0gY2RzQnkodHhkYiwgYnkgPSAidHgiLCB1c2UubmFtZXMgPSBUUlVFKQpjZHNfdHggPC0gY2RzX3R4WyJFTlNUMDAwMDAyNzU0OTMuNyJdCgppbnRieXR4IDwtIGludHJvbnNCeVRyYW5zY3JpcHQodHhkYiwgdXNlLm5hbWVzID0gVFJVRSkKaW50Ynl0eCA8LSBpbnRieXR4WyJFTlNUMDAwMDAyNzU0OTMuNyJdCgoKZml2ZV91dHIgPC0gZml2ZVVUUnNCeVRyYW5zY3JpcHQodHhkYiwgdXNlLm5hbWVzID0gVFJVRSkkRU5TVDAwMDAwMjc1NDkzLjcKdGhyZWVfdXRyIDwtIHRocmVlVVRSc0J5VHJhbnNjcmlwdCh0eGRiLCB1c2UubmFtZXMgPSBUUlVFKSRFTlNUMDAwMDAyNzU0OTMuNwpnZW5lX21vZGVsX2dyIDwtCiAgYyhmaXZlX3V0ciwgY2RzX3R4JEVOU1QwMDAwMDI3NTQ5My43LCBpbnRieXR4JEVOU1QwMDAwMDI3NTQ5My43LCB0aHJlZV91dHIpCmdlbmVfbW9kZWxfZ3IgPC0gc29ydChnZW5lX21vZGVsX2dyKQppZF9jb2wgPC0gbWNvbHMoZ2VuZV9tb2RlbF9ncikkY2RzX2lkCmlkX2NvbFsxXSA8LSAiNXV0cl8yNDcyNzkiCmlkX2NvbFs1N10gPC0gIjN1dHJfMjQ3MzMwIgppZF9jb2xbc2VxKDIsIDU2LCAyKV0gPC0gcGFzdGUwKCJjZHMiLCAxOjI4LCAiXyIsIGlkX2NvbFtzZXEoMiwgNTYsIDIpXSkKaWRfY29sW3NlcSgzLCA1NSwgMildIDwtIHBhc3RlMCgiaW50cm9uIiwgMToyNykKbWNvbHMoZ2VuZV9tb2RlbF9ncikgPC0gRGF0YUZyYW1lKGlkID0gaWRfY29sKQpjZHNfc2VxcyA8LSBleHRyYWN0VHJhbnNjcmlwdFNlcXMoaGdfZ2Vub21lLCBhcyhnZW5lX21vZGVsX2dyLCAiR1Jhbmdlc0xpc3QiKSkKbWNvbHMoZ2VuZV9tb2RlbF9ncikkc2VxIDwtIGNkc19zZXFzCmdlbmVfbW9kZWxfZ3IKYGBgCgoKYGBge3J9CmxvY19sZW5zIDwtCiAgdGliYmxlKGxvYyA9IG1jb2xzKGdlbmVfbW9kZWxfZ3IpJGlkLCBsb2NfbGVuID0gd2lkdGgoZ2VuZV9tb2RlbF9ncikpCmxvY19sZW5zCmBgYAoKCgpgYGB7cn0KRUdGUl9zZXEgPC0gZXh0cmFjdFRyYW5zY3JpcHRTZXFzKGhnX2dlbm9tZSwgY2RzX3R4KQpFR0ZSX3NlcQpgYGAKCmBgYHtyfQpFR0ZSX2FhIDwtIHRyYW5zbGF0ZShFR0ZSX3NlcSkKRUdGUl9hYQpgYGAKCgpgYGB7cn0KY2RzX3N0YXJ0cyA8LSBzdGFydChjZHNfdHgpCmNkc19lbmRzIDwtIGVuZChjZHNfdHgpCmNkc193aWR0aCA8LQogIHRyYW5zY3JpcHRXaWR0aHMoCiAgICBleG9uU3RhcnRzID0gY2RzX3N0YXJ0cywKICAgIGV4b25FbmRzID0gY2RzX2VuZHMKICApCnJlZl9sb2NzIDwtIHRyYW5zY3JpcHRMb2NzMnJlZkxvY3MobGlzdChjKDE6Y2RzX3dpZHRoKSksCiAgZXhvblN0YXJ0cyA9IGNkc19zdGFydHMsCiAgZXhvbkVuZHMgPSBjZHNfZW5kcywKICBzdHJhbmQgPSBjKCIrIikKKVtbMV1dCnJlZl9sb2NzWzE6MTBdCmBgYAoKCiMgTG9hZCwgY29tYmluZSwgYW5kIGZpbHRlciB2YXJpYW50IGRhdGEKCiMjIExvYWQgY2xpbnZhciBkYXRhCgpgYGB7cn0KY2xpbnZhcl9oZzM4X0VHRlIgPC0KICByZWFkX3RzdihjbGludmFyX0VHRlJfcGF0aCkKCmNsaW52YXJfaGczOF9FR0ZSIDwtCiAgY2xpbnZhcl9oZzM4X0VHRlIgJT4lCiAgZHBseXI6OnNlbGVjdCgKICAgIC1HZW5lSUQsIC1HZW5lU3ltYm9sLCAtSEdOQ19JRCwgLWBuc3YvZXN2IChkYlZhcilgLAogICAgLUFzc2VtYmx5LCAtQ2hyb21vc29tZUFjY2Vzc2lvbiwgLVJlZmVyZW5jZUFsbGVsZSwKICAgIC1BbHRlcm5hdGVBbGxlbGUsIC1DeXRvZ2VuZXRpYwogICkgJT4lCiAgbXV0YXRlKHZhcl9sZW4gPSBwbWF4KAogICAgc3RyX2xlbmd0aChSZWZlcmVuY2VBbGxlbGVWQ0YpLAogICAgc3RyX2xlbmd0aChBbHRlcm5hdGVBbGxlbGVWQ0YpCiAgKSkgJT4lCiAgZmlsdGVyKHZhcl9sZW4gPD0gMTApICU+JQogIGFycmFuZ2UoUG9zaXRpb25WQ0YpCgojIG9ubHkga2VlcCBtYWluIHRyYW5zY3JpcHQgdmFyaWFudHMKY2xpbnZhcl9oZzM4X0VHRlIgPC0KICBjbGludmFyX2hnMzhfRUdGUiAlPiUKICBmaWx0ZXIoTmFtZSAhPSAiTk1fMDAxMzQ2OTQxLjIoRUdGUik6Yy44OS00NTM2Xzg5LTQ1MjlkZWwiKQpjbGludmFyX2hnMzhfRUdGUgpgYGAKCgoKCmBgYHtyfQpjbGludmFyX2hnMzhfRUdGUl9yZW5hbWVkIDwtCiAgY2xpbnZhcl9oZzM4X0VHRlIgJT4lCiAgZHBseXI6OnNlbGVjdCgKICAgIE5hbWUsIFN0YXJ0LCBTdG9wLAogICAgUmVmZXJlbmNlQWxsZWxlVkNGLAogICAgQWx0ZXJuYXRlQWxsZWxlVkNGLAogICAgVmFyaWF0aW9uSUQKICApICU+JQogIHNldF9uYW1lcyhjKAogICAgIm5hbWUiLCAic3RhcnQiLCAic3RvcCIsCiAgICAicmVmIiwgImFsdCIsICJjbGludmFyX2lkIgogICkpICU+JQogIG11dGF0ZShuYW1lID0gc3RyX3JlcGxhY2UoCiAgICBuYW1lLCAiTk1fMDA1MjI4LjVcXChFR0ZSXFwpOiIsCiAgICBwYXN0ZTAoImciLCBzdGFydCwgIl8iKQogICkpICU+JQogIG11dGF0ZShjbGludmFyX2lkID0gYXMuY2hhcmFjdGVyKGNsaW52YXJfaWQpKQpjbGludmFyX2hnMzhfRUdGUl9yZW5hbWVkCmBgYAoKYGBge3J9CmNsaW52YXJfaGczOF9FR0ZSX25vdF9zbnYgPC0KICBjbGludmFyX2hnMzhfRUdGUl9yZW5hbWVkICU+JQogIGZpbHRlcighKHN0cl9sZW5ndGgocmVmKSA9PSAxICYKICAgIHN0cl9sZW5ndGgoYWx0KSA9PSAxKSkgJT4lCiAgbXV0YXRlKHR5cGUgPSBjYXNlX3doZW4oCiAgICAoc3RyX2xlbmd0aChyZWYpID09IHN0cl9sZW5ndGgoYWx0KSAmCiAgICAgIHN0cl9sZW5ndGgocmVmKSA9PSAxKSB+ICJzbnYiLAogICAgKHN0cl9zdWIocmVmLCAxLCAxKSA9PSBhbHQgJgogICAgICBzdHJfbGVuZ3RoKGFsdCkgPCBzdHJfbGVuZ3RoKHJlZikpIH4gImRlbCIsCiAgICAoc3RyX3N1YihhbHQsIDEsIDEpID09IHJlZiAmCiAgICAgIHN0cl9sZW5ndGgocmVmKSA9PSAxICYKICAgICAgc3RyX2xlbmd0aChhbHQpID4gMSkgfiAiaW5zIiwKICAgIFRSVUUgfiAiaW5kZWwiCiAgKSkgJT4lCiAgbXV0YXRlKHN0b3AgPSBpZl9lbHNlKHR5cGUgPT0gImlucyIsIHN0b3AgLSAxLCBzdG9wKSkgJT4lCiAgbXV0YXRlKAogICAgYWx0ID0gaWZfZWxzZSh0eXBlID09ICJkZWwiLCAiIiwgYWx0KSwKICAgIHJlZiA9IGlmX2Vsc2UodHlwZSA9PSAiZGVsIiwgc3RyX3N1YihyZWYsIDIpLCByZWYpCiAgKSAlPiUKICByZW5hbWUoY2xpbnZhcl9pZCA9ICJpZCIpICU+JQogIHJlbG9jYXRlKHR5cGUsIC5hZnRlciA9ICJuYW1lIikKY2xpbnZhcl9oZzM4X0VHRlJfbm90X3NudgpgYGAKCmBgYHtyfQpjbGludmFyX2hnMzhfRUdGUl9zbnYgPC0KICBjbGludmFyX2hnMzhfRUdGUl9yZW5hbWVkICU+JQogIGZpbHRlcigoc3RyX2xlbmd0aChyZWYpID09IDEgJiBzdHJfbGVuZ3RoKGFsdCkgPT0gMSkpCmNsaW52YXJfaGczOF9FR0ZSX3NudgpgYGAKCiMjIExvYWQgQ09TTUlDIGRhdGEKCgoKYGBge3J9CmNvc21pY19kdCA8LQogIHJlYWRfdHN2KGNvc21pY19wYXRoKQoKY29zbWljX2R0IDwtCiAgY29zbWljX2R0ICU+JQogIGZpbHRlcihUUkFOU0NSSVBUX0FDQ0VTU0lPTiA9PSAiRU5TVDAwMDAwMjc1NDkzLjYiKSAlPiUKICBncm91cF9ieShHRU5PTUlDX01VVEFUSU9OX0lEKSAlPiUKICBkcGx5cjo6c2xpY2UoMSkgJT4lCiAgdW5ncm91cCgpCgpjb3NtaWNfZHRfc3Vic2V0IDwtCiAgY29zbWljX2R0ICU+JQogIGRwbHlyOjpzZWxlY3QoCiAgICBNVVRBVElPTl9DRFMsIE1VVEFUSU9OX0FBLAogICAgR0VOT01FX1NUQVJULCBHRU5PTUVfU1RPUCwKICAgIEdFTk9NSUNfV1RfQUxMRUxFLCBHRU5PTUlDX01VVF9BTExFTEUsCiAgICBHRU5PTUlDX01VVEFUSU9OX0lELCBNVVRBVElPTl9ERVNDUklQVElPTgogICkgJT4lCiAgbXV0YXRlKE1VVEFUSU9OX0FBID0gc3RyX3JlcGxhY2UoTVVUQVRJT05fQUEsICJwLlxcPyIsICIiKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBpZl9lbHNlKE1VVEFUSU9OX0FBID09ICIiLAogICAgcGFzdGUwKCJnIiwgR0VOT01FX1NUQVJULCAiXyIsIE1VVEFUSU9OX0NEUyksCiAgICBwYXN0ZTAoImciLCBHRU5PTUVfU1RBUlQsICJfIiwgTVVUQVRJT05fQ0RTLCAiICgiLCBNVVRBVElPTl9BQSwgIikiKQogICkpICU+JQogIGRwbHlyOjpzZWxlY3QoCiAgICBuYW1lLCBHRU5PTUVfU1RBUlQsIEdFTk9NRV9TVE9QLAogICAgR0VOT01JQ19XVF9BTExFTEUsIEdFTk9NSUNfTVVUX0FMTEVMRSwKICAgIEdFTk9NSUNfTVVUQVRJT05fSUQKICApICU+JQogIHNldF9uYW1lcyhjKCJuYW1lIiwgInN0YXJ0IiwgInN0b3AiLCAicmVmIiwgImFsdCIsICJjb3NtaWNfaWQiKSkgJT4lCiAgbXV0YXRlKAogICAgcmVmID0gaWZfZWxzZShpcy5uYShyZWYpLCAiIiwgcmVmKSwKICAgIGFsdCA9IGlmX2Vsc2UoaXMubmEoYWx0KSwgIiIsIGFsdCkKICApICU+JQogIG11dGF0ZSh2YXJfbGVuID0gcG1heChzdHJfbGVuZ3RoKHJlZiksIHN0cl9sZW5ndGgoYWx0KSkpICU+JQogIGZpbHRlcih2YXJfbGVuIDw9IDEwKSAlPiUKICBkcGx5cjo6c2VsZWN0KC12YXJfbGVuKSAlPiUKICBhcnJhbmdlKHN0YXJ0KQoKCgpjb3NtaWNfZHRfc3Vic2V0X3NudiA8LQogIGNvc21pY19kdF9zdWJzZXQgJT4lCiAgZmlsdGVyKHN0cl9sZW5ndGgocmVmKSA9PSAxICYgc3RyX2xlbmd0aChhbHQpID09IDEpCgpjb3NtaWNfZHRfc3Vic2V0X25vdF9zbnYgPC0KICBjb3NtaWNfZHRfc3Vic2V0ICU+JQogIGZpbHRlcighKHN0cl9sZW5ndGgocmVmKSA9PSAxICYgc3RyX2xlbmd0aChhbHQpID09IDEpKQoKY29zbWljX2R0X3N1YnNldF9zbnYKYGBgCgoKYGBge3J9CmNvc21pY19kdF9zdWJzZXRfbm90X3NudiA8LQogIGNvc21pY19kdF9zdWJzZXRfbm90X3NudiAlPiUKICBtdXRhdGUodHlwZSA9IGNhc2Vfd2hlbigKICAgIChzdHJfbGVuZ3RoKHJlZikgPT0gc3RyX2xlbmd0aChhbHQpICYgc3RyX2xlbmd0aChyZWYpID09IDEpIH4gInNudiIsCiAgICAoc3RyX2xlbmd0aChyZWYpID49IDEgJiBzdHJfbGVuZ3RoKGFsdCkgPT0gMCkgfiAiZGVsIiwKICAgIChzdHJfbGVuZ3RoKHJlZikgPT0gMCAmIHN0cl9sZW5ndGgoYWx0KSA+PSAxKSB+ICJpbnMiLAogICAgVFJVRSB+ICJpbmRlbCIKICApKSAlPiUKICByZWxvY2F0ZSh0eXBlLCAuYWZ0ZXIgPSBuYW1lKQoKCmNvc21pY19kdF9zdWJzZXRfbm90X3NudiA8LQogIGNvc21pY19kdF9zdWJzZXRfbm90X3NudiAlPiUKICBtdXRhdGUoZXh0cmFfYmFzZSA9IG1hcF9jaHIoCiAgICBjb3NtaWNfZHRfc3Vic2V0X25vdF9zbnYkc3RhcnQsCiAgICB+IGFzLmNoYXJhY3RlcihzdWJzZXEoaGdfZ2Vub21lW1siY2hyNyJdXSwgLiwgLikpCiAgKSkgJT4lCiAgbXV0YXRlKAogICAgc3RvcCA9IGlmX2Vsc2UodHlwZSA9PSAiaW5zIiwgc3RvcCAtIDEsIHN0b3ApLAogICAgcmVmID0gaWZfZWxzZSh0eXBlID09ICJpbnMiLCBleHRyYV9iYXNlLCByZWYpLAogICAgYWx0ID0gaWZfZWxzZSh0eXBlID09ICJpbnMiLCBwYXN0ZTAoZXh0cmFfYmFzZSwgYWx0KSwgYWx0KQogICkgJT4lCiAgZHBseXI6OnNlbGVjdCgtZXh0cmFfYmFzZSkKY29zbWljX2R0X3N1YnNldF9ub3Rfc252CmBgYAoKYGBge3J9CnNudl9kdCA8LQogIGZ1bGxfam9pbihjb3NtaWNfZHRfc3Vic2V0X3NudiwKICAgIGNsaW52YXJfaGczOF9FR0ZSX3NudiwKICAgIGJ5ID0gYygic3RhcnQiLCAic3RvcCIsICJyZWYiLCAiYWx0IikKICApICU+JQogIG11dGF0ZShuYW1lID0gaWZfZWxzZShpcy5uYShuYW1lLngpLCBuYW1lLnksIG5hbWUueCkpICU+JQogIGRwbHlyOjpzZWxlY3QoCiAgICBuYW1lLCBzdGFydCwgc3RvcCwKICAgIHJlZiwgYWx0LCBjb3NtaWNfaWQsCiAgICBjbGludmFyX2lkCiAgKSAlPiUKICBhcnJhbmdlKHN0YXJ0KSAlPiUKICBtdXRhdGUobmFtZSA9IGdzdWIoIl9jXFwuXFxkK1srLV0/XFxkKyhbWzphbHBoYTpdXSk+IiwgIl9cXDE+IiwgbmFtZSkpCnNudl9kdApgYGAKCgojIyBMb2FkIHZhcmlhbnRzIGZyb20gYmFzZSBlZGl0b3IgZXhwZXJpbWVudHMKCmBgYHtyfQpBQkU4ZV9hbGxfZHQgPC0gcmVhZF9jc3YoQUJFOGVfcGF0aCkKQkU0bWF4X2FsbF9kdCA8LSByZWFkX2NzdihCRTRtYXhfcGF0aCkKQUJFOGVfZHQgPC0gQUJFOGVfYWxsX2R0ICU+JQogIGRwbHlyOjpzZWxlY3QoYygxNCwgMTUsIDE3LCAyMCwgMjcpKQpCRTRtYXhfZHQgPC0gQkU0bWF4X2FsbF9kdCAlPiUKICBkcGx5cjo6c2VsZWN0KGMoMTQsIDE1LCAxNywgMjAsIDI3KSkKYmFzZV9lZGl0b3JfdmFyaWFudHMgPC0KICBiaW5kX3Jvd3MoQkU0bWF4X2R0LCBBQkU4ZV9kdCkgJT4lCiAgZHBseXI6OmZpbHRlcihNdXRhdGlvbi5jYXRlZ29yeV9zaW1wbGlmaWVkICVpbiUKICAgIGMoIk5vbnNlbnNlIiwgIk1pc3NlbnNlIiwgIlNwbGljZS1hY2NlcHRvciIsICJTcGxpY2UtZG9ub3IiKSkKYmFzZV9lZGl0b3JfdmFyaWFudHMgPC0KICBiYXNlX2VkaXRvcl92YXJpYW50cyAlPiUKICBzZXBhcmF0ZV9yb3dzKE51Y2xlb3RpZGUuZWRpdHMsIHNlcCA9ICJDXyIpICU+JQogIHNlcGFyYXRlX3Jvd3MoTnVjbGVvdGlkZS5lZGl0cywgc2VwID0gIkFfIikgJT4lCiAgc2VwYXJhdGVfcm93cyhOdWNsZW90aWRlLmVkaXRzLCBzZXAgPSAiXyIpICU+JQogIHNlcGFyYXRlX3Jvd3MoTnVjbGVvdGlkZS5lZGl0cywgc2VwID0gIjsiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKE51Y2xlb3RpZGUuZWRpdHMgIT0gIiIpICU+JQogIG11dGF0ZShOdWNsZW90aWRlLmVkaXRzID0gYXMuaW50ZWdlcihOdWNsZW90aWRlLmVkaXRzKSkgJT4lCiAgbXV0YXRlKHN0YXJ0ID0gaWZfZWxzZShzZ1JOQS5TdHJhbmQgPT0gInNlbnNlIiwKICAgIHNncm5hLmdlbm9taWMucG9zaXRpb24gKyAoTnVjbGVvdGlkZS5lZGl0cyAtIDEpLAogICAgc2dybmEuZ2Vub21pYy5wb3NpdGlvbiAtIChOdWNsZW90aWRlLmVkaXRzIC0gMSkKICApKSAlPiUKICBtdXRhdGUoCiAgICBlZGl0ID0KICAgICAgY2FzZV93aGVuKAogICAgICAgIEVkaXQgPT0gIkMtVCIgJiBzZ1JOQS5TdHJhbmQgPT0gImFudGlzZW5zZSIgfiAiRy1BIiwKICAgICAgICBFZGl0ID09ICJBLUciICYgc2dSTkEuU3RyYW5kID09ICJhbnRpc2Vuc2UiIH4gIlQtQyIsCiAgICAgICAgVFJVRSB+IEVkaXQKICAgICAgKQogICkgJT4lCiAgZHBseXI6OnNlbGVjdChzdGFydCwgZWRpdCkgJT4lCiAgZ3JvdXBfYnkoc3RhcnQpICU+JQogIGRwbHlyOjpzbGljZSgxKSAlPiUKICB0aWR5cjo6c2VwYXJhdGUoZWRpdCwKICAgIGludG8gPSBjKCJyZWYiLCAiYWx0IiksIHNlcCA9ICItIgogICkgJT4lCiAgbXV0YXRlKAogICAgc3RvcCA9IHN0YXJ0LAogICAgbmFtZSA9IHBhc3RlMCgiZyIsIHN0YXJ0LCAiXyIsIHJlZiwgIj4iLCBhbHQpCiAgKSAlPiUKICBkcGx5cjo6c2VsZWN0KGMoIm5hbWUiLCAic3RhcnQiLCAic3RvcCIsICJyZWYiLCAiYWx0IikpCmJhc2VfZWRpdG9yX3ZhcmlhbnRzCmBgYAoKCiMjIyBDb21iaW5lIHZhcmlhbnRzIGRhdGEKCmBgYHtyfQpzbnZfZHQgPC0KICBmdWxsX2pvaW4oc252X2R0LAogICAgYmFzZV9lZGl0b3JfdmFyaWFudHMsCiAgICBieSA9IGMoInN0YXJ0IiwgInN0b3AiLCAicmVmIiwgImFsdCIpCiAgKQoKc252X2R0IDwtCiAgc252X2R0ICU+JQogIG11dGF0ZShuYW1lID0gaWZfZWxzZShpcy5uYShuYW1lLngpLCBuYW1lLnksIG5hbWUueCkpICU+JQogIHJlbmFtZShuYW1lLnkgPSAiYmVfaWQiKSAlPiUKICBkcGx5cjo6c2VsZWN0KAogICAgbmFtZSwgc3RhcnQsIHN0b3AsIHJlZiwKICAgIGFsdCwgY29zbWljX2lkLCBjbGludmFyX2lkLCBiZV9pZAogICkgJT4lCiAgdW5pdGUoImlkIiwgY29zbWljX2lkOmJlX2lkLCBzZXAgPSAiOyIsIG5hLnJtID0gVFJVRSkgJT4lCiAgYXJyYW5nZShzdGFydCkgJT4lCiAgbXV0YXRlKHR5cGUgPSAic252IikKc252X2R0CmBgYAoKCmBgYHtyfQpub25fc252X2R0IDwtCiAgZnVsbF9qb2luKGNsaW52YXJfaGczOF9FR0ZSX25vdF9zbnYsCiAgICBjb3NtaWNfZHRfc3Vic2V0X25vdF9zbnYsCiAgICBieSA9IGMoInN0YXJ0IiwgInN0b3AiLCAicmVmIiwgImFsdCIsICJ0eXBlIikKICApICU+JQogIG11dGF0ZShuYW1lID0gaWZfZWxzZShpcy5uYShuYW1lLngpLCBuYW1lLnksIG5hbWUueCkpICU+JQogIGRwbHlyOjpzZWxlY3QoCiAgICBuYW1lLCB0eXBlLCBzdGFydCwgc3RvcCwKICAgIHJlZiwgYWx0LCBjb3NtaWNfaWQsCiAgICBpZAogICkgJT4lCiAgYXJyYW5nZShzdGFydCkgJT4lCiAgdW5pdGUoImlkIiwgY29zbWljX2lkOmlkLCBzZXAgPSAiOyIsIG5hLnJtID0gVFJVRSkKbm9uX3Nudl9kdApgYGAKCgpgYGB7cn0KdmFyaWFudHNfZHQgPC0KICBiaW5kX3Jvd3MoCiAgICBzbnZfZHQsCiAgICBub25fc252X2R0CiAgKSAlPiUKICBhcnJhbmdlKHN0YXJ0KSAlPiUKICBtdXRhdGUobmFtZSA9IHN1YigiIFxcKHBcXC4uKiQiLCAiIiwgbmFtZSkpCgp2YXJpYW50c19kdApgYGAKCgoKCiMjIEFubm90YXRlIFZhcmlhbnRzCgoKYGBge3J9CmFubm90YXRlX2FuZF9wcmVkaWN0X3ZhcmlhbnRzIDwtIGZ1bmN0aW9uKHZhcmlhbnRzX2R0KSB7CiAgc2VxX2xlbl9taW4gPC0gNDkKCiAgbnVtX3ZhcmlhbnRzIDwtIE5ST1codmFyaWFudHNfZHQpCiAgZ3IwIDwtCiAgICBHUmFuZ2VzKAogICAgICBSbGUoYygiY2hyNyIpLCBudW1fdmFyaWFudHMpLAogICAgICBJUmFuZ2VzKAogICAgICAgIHN0YXJ0ID0gdmFyaWFudHNfZHQkc3RhcnQsCiAgICAgICAgZW5kID0gdmFyaWFudHNfZHQkc3RvcCwKICAgICAgICBuYW1lcyA9IHZhcmlhbnRzX2R0JG5hbWUKICAgICAgKQogICAgKQoKICB2YXJfYWxsZWxsZXMgPC0gRE5BU3RyaW5nU2V0KHZhcmlhbnRzX2R0JGFsdCkKCiAgaW50cm9uX2xvY2F0aW9ucyA8LQogICAgbG9jYXRlVmFyaWFudHMoZ3IwLAogICAgICBpbnRieXR4LAogICAgICBJbnRyb25WYXJpYW50cygpLAogICAgICB2YXJBbGxlbGUgPSB2YXJfYWxsZWxsZXMKICAgICkKICAjIExvY2F0ZSBpbnRyb25pYyB2YXJpYW50cwogIGludHJvbl9sb2NhdGlvbnMgPC0KICAgIGludHJvbl9sb2NhdGlvbnMgJT4lCiAgICBhc190aWJibGUoKSAlPiUKICAgIGFkZF9jb2x1bW4obmFtZSA9IG5hbWVzKGludHJvbl9sb2NhdGlvbnMpKSAlPiUKICAgIHJlbG9jYXRlKG5hbWUsIC5iZWZvcmUgPSAic2VxbmFtZXMiKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLVBSRUNFREVJRCwgLUZPTExPV0lELCAtVFhJRCkKCiAgIyBMb2NhdGUgcmVtYWluaW5nIHZhcmlhbnRzCiAgYWxsIDwtIGxvY2F0ZVZhcmlhbnRzKGdyMCwKICAgIHR4ZGIsCiAgICBBbGxWYXJpYW50cygpLAogICAgdmFyQWxsZWxlID0gdmFyX2FsbGVsbGVzCiAgKQogIGFsbCA8LQogICAgYWxsICU+JQogICAgYXNfdGliYmxlKCkgJT4lCiAgICBhZGRfY29sdW1uKG5hbWUgPSBuYW1lcyhhbGwpKSAlPiUKICAgIHJlbG9jYXRlKG5hbWUsIC5iZWZvcmUgPSAic2VxbmFtZXMiKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLVBSRUNFREVJRCwgLUZPTExPV0lEKQoKICAjIEZsYWcgaW50cm9uaWMgYW5kIDVVVFIgdmFyaWFudHMgdGhhdCBoYXZlIGFsdGVybmF0aXZlIAogICMgZWZmZWN0cyBnaXZlbiBvdGhlciBwb3RlbnRpYWwgc3BsaWNlZCB0cmFuc2NyaXB0cwoKICB0cmFuc2NyaXB0X3NwbGljZV9zaXRlcyA8LQogICAgYWxsICU+JQogICAgZHBseXI6OmZpbHRlcihMT0NBVElPTiA9PSAic3BsaWNlU2l0ZSIgJiBUWElEID09ICI5MzUwMiIpCgogIGludHJvbl9sb2NhdGlvbnMgPC0KICAgIGludHJvbl9sb2NhdGlvbnMgJT4lCiAgICBmaWx0ZXIoIShuYW1lICVpbiUgdHJhbnNjcmlwdF9zcGxpY2Vfc2l0ZXMkbmFtZSkpCgogIHVuY2VydGFpbl9pbnRyb25zIDwtCiAgICBhbGwgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG5hbWUgJWluJSBpbnRyb25fbG9jYXRpb25zJG5hbWUpICU+JQogICAgZ3JvdXBfYnkobmFtZSwgTE9DQVRJT04pICU+JQogICAgZHBseXI6OnNsaWNlKDEpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgZ3JvdXBfYnkobmFtZSkgJT4lCiAgICBtdXRhdGUoZnJhY19pbnRyb24gPSBzdW0oTE9DQVRJT04gPT0gImludHJvbiIpIC8gbigpKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoZnJhY19pbnRyb24gPCAxKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoTE9DQVRJT04gIT0gImludHJvbiIpICU+JQogICAgZHBseXI6OmZpbHRlcihUWElEICE9IDkzNTAyKSAlPiUKICAgIGFycmFuZ2UoUVVFUllJRCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KC1HRU5FSUQsIC1mcmFjX2ludHJvbikgJT4lCiAgICB1bmdyb3VwKCkKCiAgZmxhZ192YXJpYW50cyA8LQogICAgdW5jZXJ0YWluX2ludHJvbnMgJT4lCiAgICBkcGx5cjo6c2VsZWN0KG5hbWUsIExPQ0FUSU9OLCBUWElEKSAlPiUKICAgIGxlZnRfam9pbiguLCB0eF9sZW5ndGhzICU+JQogICAgICBkcGx5cjo6c2VsZWN0KHR4X2lkLCB0eF9uYW1lKSAlPiUKICAgICAgbXV0YXRlKHR4X2lkID0gYXMuY2hhcmFjdGVyKHR4X2lkKSkgJT4lCiAgICAgIGRwbHlyOjpyZW5hbWUoVFhJRCA9ICJ0eF9pZCIpLAogICAgYnkgPSAiVFhJRCIKICAgICkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KC1UWElEKSAlPiUKICAgIHVuaXRlKCJhbHRfZWZmZWN0IiwgTE9DQVRJT046dHhfbmFtZSkKCgogIGFsbCA8LQogICAgYWxsICU+JQogICAgZHBseXI6OmZpbHRlcihUWElEID09IDkzNTAyKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLVRYSUQpCgogIHBvdGVudGlhbF9wcm9tb3RlcnMgPC0KICAgIGFsbFt3aGljaChkdXBsaWNhdGVkKGFsbCRuYW1lKSksIF0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KG5hbWUpICU+JQogICAgbXV0YXRlKGFsdF9lZmZlY3QgPSAicHJvbW90ZXJfRU5TVDAwMDAwMjc1NDkzLjciKQoKICBmbGFnX3ZhcmlhbnRzIDwtCiAgICBiaW5kX3Jvd3MoZmxhZ192YXJpYW50cywgcG90ZW50aWFsX3Byb21vdGVycykKCiAgZmxhZ192YXJpYW50cyA8LQogICAgZmxhZ192YXJpYW50cyAlPiUKICAgIGdyb3VwX2J5KG5hbWUpICU+JQogICAgZHBseXI6OnNsaWNlKDEpICU+JQogICAgdW5ncm91cCgpCgoKICBhbGwgPC0KICAgIGFsbCAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWR1cGxpY2F0ZWQoYWxsJG5hbWUpKQoKCiAgYWxsIDwtCiAgICBiaW5kX3Jvd3MoCiAgICAgIGFsbCwKICAgICAgaW50cm9uX2xvY2F0aW9ucwogICAgKQoKICBhbGwgPC0KICAgIGxlZnRfam9pbihhbGwsIGZsYWdfdmFyaWFudHMsIGJ5ID0gIm5hbWUiKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLUdFTkVJRCkKCgogIGFsbCA8LQogICAgYWxsICU+JQogICAgZHBseXI6OnNlbGVjdCgtYyhMT0NTVEFSVDpDRFNJRCkpCgogIGdlbmVfbW9kZWxfZ3JfbGlzdCA8LQogICAgYXMoZ2VuZV9tb2RlbF9nciwgIkdSYW5nZXNMaXN0IikKCiAgbmFtZXMoZ2VuZV9tb2RlbF9ncl9saXN0KSA8LSBtY29scyhnZW5lX21vZGVsX2dyKSRpZAoKICBtYXBfZ3JzIDwtCiAgICBtYXBUb1RyYW5zY3JpcHRzKHJlc2l6ZShncjAsIDEpLCBnZW5lX21vZGVsX2dyX2xpc3QpCgogIG1hcF9kdCA8LQogICAgbWFwX2dycyAlPiUKICAgIGFzX3RpYmJsZSgpICU+JQogICAgbXV0YXRlKG5hbWUgPSBuYW1lcyhtYXBfZ3JzKSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KG5hbWUsIHNlcW5hbWVzLCBzdGFydCkgJT4lCiAgICBzZXRfbmFtZXMoYygibmFtZSIsICJsb2MiLCAibG9jX3N0YXJ0IikpICU+JQogICAgbGVmdF9qb2luKC4sIGxvY19sZW5zLCBieSA9ICJsb2MiKQoKICBhbGwgPC0KICAgIGxlZnRfam9pbihhbGwsCiAgICAgIG1hcF9kdCwKICAgICAgYnkgPSAibmFtZSIKICAgICkKCiAgIyBQcmVkaWN0IGNvbnNlcXVlbmNlIG9mIHZhcmlhbnQKICBwcmVkaWN0X2NvZGluZ192YXJpYW50cyA8LQogICAgcHJlZGljdENvZGluZyhncjAsIHR4ZGIsIGhnX2dlbm9tZSwgdmFyQWxsZWxlID0gdmFyX2FsbGVsbGVzKQogIHByZWRpY3RfY29kaW5nX3ZhcmlhbnRzIDwtCiAgICBwcmVkaWN0X2NvZGluZ192YXJpYW50c1ttY29scyhwcmVkaWN0X2NvZGluZ192YXJpYW50cykkVFhJRCA9PSA5MzUwMl0KICBwcmVkaWN0X2NvZGluZ192YXJpYW50cyA8LQogICAgYXNfdGliYmxlKHByZWRpY3RfY29kaW5nX3ZhcmlhbnRzKSAlPiUKICAgIGFkZF9jb2x1bW4obmFtZSA9IG5hbWVzKHByZWRpY3RfY29kaW5nX3ZhcmlhbnRzKSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KAogICAgICBuYW1lLCBDRFNMT0Muc3RhcnQsIENPTlNFUVVFTkNFLCBSRUZDT0RPTiwKICAgICAgVkFSQ09ET04sIFJFRkFBLCBWQVJBQSwgUFJPVEVJTkxPQwogICAgKQoKICBuX2Rpc3RpbmN0KGFsbCRuYW1lKQoKICBhbGwgPC0KICAgIGxlZnRfam9pbihhbGwsIHByZWRpY3RfY29kaW5nX3ZhcmlhbnRzLCBieSA9ICJuYW1lIikKCgoKICBhbGwgPC0KICAgIGFsbCAlPiUKICAgIG11dGF0ZShsb2NfZW5kX2NvbXAgPSBsb2NfbGVuIC0gKGxvY19zdGFydCArIHdpZHRoIC0gMSkpICU+JQogICAgbXV0YXRlKGJvdW5kYXJ5X2ZsYWcgPSAoTE9DQVRJT04gPT0gImNvZGluZyIgJgogICAgICAobG9jX3N0YXJ0IDwgc2VxX2xlbl9taW4gfCBsb2NfZW5kX2NvbXAgPCBzZXFfbGVuX21pbikpKQoKICBhbGwgPC0KICAgIGFsbCAlPiUKICAgIGRwbHlyOjpzZWxlY3QoCiAgICAgIG5hbWUsIENPTlNFUVVFTkNFLCBMT0NBVElPTiwgbG9jLCBsb2NfbGVuLCBsb2Nfc3RhcnQsCiAgICAgIENEU0xPQy5zdGFydCwgUFJPVEVJTkxPQywgUkVGQ09ET04sIFZBUkNPRE9OLAogICAgICBSRUZBQSwgVkFSQUEsIGJvdW5kYXJ5X2ZsYWcsIGFsdF9lZmZlY3QKICAgICkgJT4lCiAgICBzZXRfbmFtZXMoYygKICAgICAgIm5hbWUiLCAiY29uc2VxdWVuY2UiLCAibG9jYXRpb24iLCAicmVnaW9uIiwgInJlZ2lvbl9sZW4iLAogICAgICAicG9zX3JlZ2lvbiIsICJwb3NfY2RzIiwgInBvc19wcm90ZWluIiwgInJlZl9jb2RvbiIsCiAgICAgICJ2YXJfY29kb24iLCAicmVmX2FhIiwgInZhcl9hYSIsICJib3VuZGFyeV9mbGFnIiwgImFsdF9lZmZlY3QiCiAgICApKSAlPiUKICAgIHJvd3dpc2UoKSAlPiUKICAgIG11dGF0ZShwb3NfcHJvdGVpbiA9IHN0cl9jKHBvc19wcm90ZWluLCBjb2xsYXBzZSA9ICI6IikpCgogIHJldHVybihhbGwpCn0KYGBgCgoKYGBge3J9CmFsbCA8LQogIGFubm90YXRlX2FuZF9wcmVkaWN0X3ZhcmlhbnRzKHZhcmlhbnRzX2R0KQpgYGAKCgojIyBJbmNsdWRlIGJhc2UgZWRpdGluZyB2YXJpYW50cyBnZW5lcmF0ZWQgYnkgdHdvIG9yIG1vcmUgZWRpdHMKCmBgYHtyfQptaW5fYmFzZV9jaGFuZ2VzIDwtIGZ1bmN0aW9uKHRhcmdldF9hbWlub19hY2lkLCByZWZfY29kb24pIHsKICAjIERlZmluZSBhIG1hcHBpbmcgb2YgYW1pbm8gYWNpZHMgdG8gY29kb25zCiAgYW1pbm9fYWNpZF9tYXBwaW5nIDwtIGxpc3QoCiAgICAiQSIgPSBjKCJHQ1QiLCAiR0NDIiwgIkdDQSIsICJHQ0ciKSwKICAgICJSIiA9IGMoIkNHVCIsICJDR0MiLCAiQ0dBIiwgIkNHRyIsICJBR0EiLCAiQUdHIiksCiAgICAiTiIgPSBjKCJBQVQiLCAiQUFDIiksCiAgICAiRCIgPSBjKCJHQVQiLCAiR0FDIiksCiAgICAiQyIgPSBjKCJUR1QiLCAiVEdDIiksCiAgICAiUSIgPSBjKCJDQUEiLCAiQ0FHIiksCiAgICAiRSIgPSBjKCJHQUEiLCAiR0FHIiksCiAgICAiRyIgPSBjKCJHR1QiLCAiR0dDIiwgIkdHQSIsICJHR0ciKSwKICAgICJIIiA9IGMoIkNBVCIsICJDQUMiKSwKICAgICJJIiA9IGMoIkFUQSIpLCAjICJBVFQiLCAiQVRDIiwgdHdvIEE+VHMKICAgICJMIiA9IGMoIlRUQSIsICJUVEciLCAiQ1RUIiwgIkNUQyIsICJDVEEiLCAiQ1RHIiksCiAgICAiSyIgPSBjKCJBQUEiLCAiQUFHIiksCiAgICAiTSIgPSBjKCJBVEciKSwKICAgICJGIiA9IGMoIlRUVCIsICJUVEMiKSwKICAgICJQIiA9IGMoIkNDVCIsICJDQ0MiLCAiQ0NBIiwgIkNDRyIpLAogICAgIlMiID0gYygiVENUIiwgIlRDQyIsICJUQ0EiLCAiVENHIiwgIkFHVCIsICJBR0MiKSwKICAgICJUIiA9IGMoIkFDVCIsICJBQ0MiLCAiQUNBIiwgIkFDRyIpLAogICAgIlciID0gYygiVEdHIiksCiAgICAiWSIgPSBjKCJUQVQiLCAiVEFDIiksCiAgICAiViIgPSBjKCJHVFQiLCAiR1RDIiwgIkdUQSIsICJHVEciKSwKICAgICIqIiA9IGMoIlRBQSIsICJUQUciLCAiVEdBIikKICApCgogICMgRmluZCB0aGUgcmVmZXJlbmNlIGFtaW5vIGFjaWQgY29ycmVzcG9uZGluZyB0byB0aGUgcmVmZXJlbmNlIGNvZG9uCiAgcmVmX2FtaW5vX2FjaWQgPC0KICAgIG5hbWVzKGFtaW5vX2FjaWRfbWFwcGluZylbd2hpY2gocmVmX2NvZG9uICVpbiUgdW5saXN0KGFtaW5vX2FjaWRfbWFwcGluZykpXQoKICAjIENoZWNrIGlmIHRoZSByZWZlcmVuY2UgYW1pbm8gYWNpZCBpcyB2YWxpZAogIGlmIChpcy5udWxsKHJlZl9hbWlub19hY2lkKSkgewogICAgc3RvcCgiSW52YWxpZCByZWZlcmVuY2UgY29kb24uIikKICB9CgogICMgQ2hlY2sgaWYgdGhlIHRhcmdldCBhbWlubyBhY2lkIGlzIHZhbGlkCiAgaWYgKCEodGFyZ2V0X2FtaW5vX2FjaWQgJWluJSBuYW1lcyhhbWlub19hY2lkX21hcHBpbmcpKSkgewogICAgc3RvcCgiSW52YWxpZCB0YXJnZXQgYW1pbm8gYWNpZC4iKQogIH0KCiAgIyBGaW5kIHRoZSB0YXJnZXQgY29kb25zIGZvciB0aGUgZ2l2ZW4gYW1pbm8gYWNpZAogIHRhcmdldF9jb2RvbnMgPC0gYW1pbm9fYWNpZF9tYXBwaW5nW1t0YXJnZXRfYW1pbm9fYWNpZF1dCgogICMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgYmFzZSBjaGFuZ2VzIG5lZWRlZCBmb3IgZWFjaCB0YXJnZXQgY29kb24KICBiYXNlX2NoYW5nZXMgPC0KICAgIHNhcHBseSgKICAgICAgdGFyZ2V0X2NvZG9ucywKICAgICAgZnVuY3Rpb24odGMpIHN1bShzdHJzcGxpdChyZWZfY29kb24sICIiKVtbMV1dICE9IHN0cnNwbGl0KHRjLCAiIilbWzFdXSkKICAgICkKCiAgIyBGaW5kIHRoZSBpbmRleCBvZiB0aGUgbWluaW11bSBiYXNlIGNoYW5nZXMKICBtaW5faW5kZXggPC0KICAgIHdoaWNoLm1pbihiYXNlX2NoYW5nZXMpCgogICMgUmV0dXJuIHRoZSB2YXJpYW50IGNvZG9uIHdpdGggbWluaW11bSBiYXNlIGNoYW5nZXMKICByZXR1cm4odGFyZ2V0X2NvZG9uc1ttaW5faW5kZXhdKQp9CgpnZXRfY29kb25fYXRfYWFfcG9zaXRpb24gPC0gZnVuY3Rpb24ocG9zKSB7CiAgc3RhcnRfcG9zIDwtIHBvcyAqIDMgLSAyCiAgZW5kX3BvcyA8LSBwb3MgKiAzCiAgYXMuY2hhcmFjdGVyKHN1YnNlcShFR0ZSX3NlcSwgc3RhcnRfcG9zLCBlbmRfcG9zKSkKfQoKCkFCRThlX2FhX3ZhciA8LQogIEFCRThlX2FsbF9kdCAlPiUKICBkcGx5cjo6c2VsZWN0KEFtaW5vLmFjaWQuZWRpdHMpICU+JQogIHNlcGFyYXRlX3Jvd3MoQW1pbm8uYWNpZC5lZGl0cywgc2VwID0gIjsiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCEoQW1pbm8uYWNpZC5lZGl0cyAlaW4lIGMoInV0ciIsICJOb25lIiwgIiIpKSkgJT4lCiAgZHBseXI6OmZpbHRlcighc3RyX2RldGVjdChBbWluby5hY2lkLmVkaXRzLCAiRXhvbiIpKSAlPiUKICBzZXBhcmF0ZV93aWRlcl9yZWdleChBbWluby5hY2lkLmVkaXRzLAogICAgYygKICAgICAgcmVmX2FhID0gIl5bQS1aYS16XSsiLAogICAgICBwb3NfcHJvdGVpbiA9ICJbMC05XSsiLAogICAgICB2YXJfYWEgPSAiW0EtWmEtel0rJCIKICAgICksCiAgICBjb2xzX3JlbW92ZSA9IEYKICApICU+JQogIGRwbHlyOjpmaWx0ZXIocmVmX2FhICE9IHZhcl9hYSkKCgpCRTRtYXhfYWFfdmFyIDwtCiAgQkU0bWF4X2FsbF9kdCAlPiUKICBkcGx5cjo6c2VsZWN0KEFtaW5vLmFjaWQuZWRpdHMpICU+JQogIHNlcGFyYXRlX3Jvd3MoQW1pbm8uYWNpZC5lZGl0cywgc2VwID0gIjsiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCEoQW1pbm8uYWNpZC5lZGl0cyAlaW4lIGMoInV0ciIsICJOb25lIiwgIiIpKSkgJT4lCiAgZHBseXI6OmZpbHRlcighc3RyX2RldGVjdChBbWluby5hY2lkLmVkaXRzLCAiRXhvbiIpKSAlPiUKICBzZXBhcmF0ZV93aWRlcl9yZWdleChBbWluby5hY2lkLmVkaXRzLAogICAgYygKICAgICAgcmVmX2FhID0gIl5bQS1aYS16XSsiLAogICAgICBwb3NfcHJvdGVpbiA9ICJbMC05XSsiLAogICAgICB2YXJfYWEgPSAiW0EtWmEtel0rJCIKICAgICksCiAgICBjb2xzX3JlbW92ZSA9IEYKICApICU+JQogIGRwbHlyOjpmaWx0ZXIocmVmX2FhICE9IHZhcl9hYSkKCmFhX21hcCA8LSBjKEFNSU5PX0FDSURfQ09ERSwgIioiID0gIlRlciIpCmZsaXBwZWRfYWFfbWFwIDwtIHNldE5hbWVzKG5hbWVzKGFhX21hcCksIGFhX21hcCkKCmJlX3Zhcl9kdCA8LQogIGJpbmRfcm93cyhBQkU4ZV9hYV92YXIsIEJFNG1heF9hYV92YXIpICU+JQogIGdyb3VwX2J5KEFtaW5vLmFjaWQuZWRpdHMpICU+JQogIGRwbHlyOjpzbGljZSgxKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKAogICAgcmVmX2FhID0gZmxpcHBlZF9hYV9tYXBbcmVmX2FhXSwKICAgIHZhcl9hYSA9IGZsaXBwZWRfYWFfbWFwW3Zhcl9hYV0KICApCgp2YXJpYW50c19kdDAgPC0KICBsZWZ0X2pvaW4odmFyaWFudHNfZHQsIGFsbCwgYnkgPSAibmFtZSIpCgpiZV92YXJfZHQgPC0KICBsZWZ0X2pvaW4oYmVfdmFyX2R0LAogICAgdmFyaWFudHNfZHQwICU+JQogICAgICBmaWx0ZXIocG9zX3Byb3RlaW4gIT0gIiIgJiB0eXBlID09ICJzbnYiKSAlPiUKICAgICAgZHBseXI6OnNlbGVjdChuYW1lLCByZWZfYWEsIHBvc19wcm90ZWluLCB2YXJfYWEpLAogICAgYnkgPSBjKCJyZWZfYWEiLCAicG9zX3Byb3RlaW4iLCAidmFyX2FhIikKICApICU+JQogIGRwbHlyOjpmaWx0ZXIoaXMubmEobmFtZSkpICU+JQogIG11dGF0ZShwb3NfcHJvdGVpbiA9IGFzLm51bWVyaWMocG9zX3Byb3RlaW4pKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKHJlZl9jb2RvbiA9IGdldF9jb2Rvbl9hdF9hYV9wb3NpdGlvbihwb3NfcHJvdGVpbikpCgpiZV92YXJfZHQgPC0KICBiZV92YXJfZHQgJT4lCiAgbXV0YXRlKHZhcl9jb2RvbiA9IG1pbl9iYXNlX2NoYW5nZXModmFyX2FhLCByZWZfY29kb24pKQoKYmVfdmFyX2R0IDwtCiAgYmVfdmFyX2R0ICU+JQogIG11dGF0ZSgKICAgIGxhc3RfYmFzZV9kaWZmID0KICAgICAgc3RyX3N1YihyZWZfY29kb24sIDMsIDMpICE9IHN0cl9zdWIodmFyX2NvZG9uLCAzLCAzKQogICkgJT4lCiAgbXV0YXRlKAogICAgcmVmID0gaWZfZWxzZShsYXN0X2Jhc2VfZGlmZiwgcmVmX2NvZG9uLCBzdHJfc3ViKHJlZl9jb2RvbiwgMSwgMikpLAogICAgYWx0ID0gaWZfZWxzZShsYXN0X2Jhc2VfZGlmZiwgdmFyX2NvZG9uLCBzdHJfc3ViKHZhcl9jb2RvbiwgMSwgMikpLAogICAgc3RhcnQgPSByZWZfbG9jc1twb3NfcHJvdGVpbiAqIDMgLSAyXSwKICAgIHN0b3AgPSBpZl9lbHNlKGxhc3RfYmFzZV9kaWZmLCBzdGFydCArIDIsIHN0YXJ0ICsgMSkKICApICU+JQogIG11dGF0ZShuYW1lID0gcGFzdGUwKCJnIiwgc3RhcnQsICJfIiwgcmVmLCAiPiIsIGFsdCkpICU+JQogIG11dGF0ZSgKICAgIGlkID0gbmFtZSwKICAgIHR5cGUgPSAiaW5kZWwiCiAgKSAlPiUKICBkcGx5cjo6c2VsZWN0KGMoIm5hbWUiLCAidHlwZSIsICJzdGFydCIsICJzdG9wIiwgInJlZiIsICJhbHQiLCAiaWQiKSkKcm0odmFyaWFudHNfZHQwKQoKIyByZW1vdmUgZzU1MTc0Nzc2X1RUPkNDIHNpbmNlIGl0IGlzIHRoZSBzYW1lIGFzIGc1NTE3NDc3Nl9jLjIyMzlfMjI0MGRlbGluc0NDCmJlX3Zhcl9kdCA8LQogIGJlX3Zhcl9kdCAlPiUKICBmaWx0ZXIobmFtZSAhPSAiZzU1MTc0Nzc2X1RUPkNDIikKYmVfdmFyX2R0CmBgYAoKCgoKIyMjIEluY2x1ZGUgZG91YmxlIGJhc2UgZWRpdHMgdmFyaWFudHMKCmBgYHtyfQp2YXJpYW50c19kdCA8LQogIGJpbmRfcm93cyh2YXJpYW50c19kdCwgYmVfdmFyX2R0KSAlPiUKICBhcnJhbmdlKHN0YXJ0KQpgYGAKCgojIyMgUmVhbm5vdGF0ZSBhZnRlciBpbmNsdXNpb24gb2YgZG91YmxlIGJhc2UgZWRpdHMgdmFyaWFudHMKCmBgYHtyfQphbGwgPC0KICBhbm5vdGF0ZV9hbmRfcHJlZGljdF92YXJpYW50cyh2YXJpYW50c19kdCkKCnZhcmlhbnRzX2R0IDwtCiAgbGVmdF9qb2luKHZhcmlhbnRzX2R0LCBhbGwsIGJ5ID0gIm5hbWUiKQoKdmFyaWFudHNfZHQKYGBgCmBgYHtyfQp0YWJsZSh2YXJpYW50c19kdCRsb2NhdGlvbikKYGBgCgpgYGB7cn0KdGFibGUodmFyaWFudHNfZHQkbG9jYXRpb24sIHZhcmlhbnRzX2R0JHR5cGUpCmBgYAoKCiMjIyBGaWx0ZXIgb3V0IGludHJvbnMKCgpgYGB7cn0KdmFyaWFudHNfZHQgPC0KICB2YXJpYW50c19kdCAlPiUKICBmaWx0ZXIobG9jYXRpb24gIT0gYygiaW50cm9uIikpCnZhcmlhbnRzX2R0CmBgYAoKCgojIyBHZW5lcmF0ZSBzeW5vbnltb3VzIG11dGF0aW9ucyBuZWFyIHRhcmdldCBTaW5nbGUgTnVjbGVvdGlkZSBWYXJpYW50cwoKCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHNwbGl0IGEgc3RyaW5nIGludG8gY29uc2VjdXRpdmUgdHJpcGxldHMKc3BsaXRfaW50b190cmlwbGV0cyA8LSBmdW5jdGlvbihzKSB7CiAgbiA8LSBuY2hhcihzKQogIGlmIChuICUlIDMgIT0gMCkgewogICAgd2FybmluZygiU3RyaW5nIGxlbmd0aCBpcyBub3QgYSBtdWx0aXBsZSBvZiAzLiBQYWRkaW5nIHdpdGggc3BhY2VzLiIpCiAgICBzIDwtIHBhc3RlMChzLCByZXAoIiAiLCAzIC0gKG4gJSUgMykpKQogIH0KICBtYXRyaXgoc3Ryc3BsaXQocywgIiIpW1sxXV0sIG5jb2wgPSAzLCBieXJvdyA9IFRSVUUpCn0KCiMgU3BsaXQgdGhlIHZlY3RvciBpbnRvIHRyaXBsZXRzCnRyaXBsZXRzIDwtIHNwbGl0X2ludG9fdHJpcGxldHMoYXMuY2hhcmFjdGVyKEVHRlJfc2VxKSkKCiMgQ3JlYXRlIGEgZGF0YWZyYW1lCmNvZG9uX21hcF9kZiA8LQogIHRpYmJsZShyZWZfY29kb24gPSBhcHBseSh0cmlwbGV0cywgMSwgcGFzdGUsIGNvbGxhcHNlID0gIiIpKSAlPiUKICBtdXRhdGUocG9zX3Byb3RlaW4gPSByb3dfbnVtYmVyKCkpCmNvZG9uX21hcF9kZgpgYGAKCgpgYGB7cn0Kc3luX2NvZG9uX21hcCA8LQogIHJlYWRfZGVsaW0oc3luX2NvZG9uX3BhdGgpCnN5bl9jb2Rvbl9tYXAKYGBgCgpgYGB7cn0KY29kb25fbWFwX2RmIDwtCiAgbGVmdF9qb2luKGNvZG9uX21hcF9kZiwgc3luX2NvZG9uX21hcCwgYnkgPSAicmVmX2NvZG9uIikgJT4lCiAgbXV0YXRlKHN0YXJ0ID0gcmVmX2xvY3NbcG9zX3Byb3RlaW4gKiAzXSkgJT4lCiAgZmlsdGVyKCFpcy5uYShyZWZfYWEpKQpjb2Rvbl9tYXBfZGYKYGBgCgoKCiMjIyBTcGxpdCBTTlZTIGludG8gc3BsaWNlU2l0ZSBjb2RpbmcsIGFuZCBpbnRyb24gdmFyaWFudHMKCmBgYHtyfQp2YXJpYW50c19zbnYgPC0KICB2YXJpYW50c19kdCAlPiUKICBmaWx0ZXIodHlwZSA9PSAic252IikKCnZhcmlhbnRzX3Nudl9jb2RpbmcgPC0KICB2YXJpYW50c19zbnYgJT4lCiAgZmlsdGVyKGxvY2F0aW9uICVpbiUgYygiY29kaW5nIikpCmBgYAoKIyMjIEZpbmQgbm9uc3lub21vdXMgbXV0YXRpb25zCgpgYGB7cn0KZ2V0X2NvZG9uX21hcCA8LSBmdW5jdGlvbihzdGFydCwgbmFtZSwgbnVtX2lkeCkgewogIGRpcyA8LSBhYnMoc3RhcnQgLSBjb2Rvbl9tYXBfZGYkc3RhcnQpCiAgZGlzW2RpcyA8PSAyXSA8LSAxMDAwMAogIGxvd2VzdF9pbmRpY2VzIDwtIGhlYWQob3JkZXIoZGlzKSwgbnVtX2lkeCkKCiAgYnBfZGlzdCA8LSBjb2Rvbl9tYXBfZGYkc3RhcnRbbG93ZXN0X2luZGljZXNdIC0gc3RhcnQKCiAgZHQgPC0gdGliYmxlKG5hbWUgPSBuYW1lLCBkaXN0ID0gYnBfZGlzdCkKICBkdCA8LSBiaW5kX2NvbHMoZHQsIGNvZG9uX21hcF9kZltsb3dlc3RfaW5kaWNlcywgXSkKICByZXR1cm4oZHQpCn0KCmNvZGluZ19zeW4gPC0KICBtYXAyX2RmKHZhcmlhbnRzX3Nudl9jb2Rpbmckc3RhcnQsCiAgICB2YXJpYW50c19zbnZfY29kaW5nJG5hbWUsCiAgICBnZXRfY29kb25fbWFwLAogICAgbnVtX2lkeCA9IDEKICApICU+JQogIHJlbmFtZShuYW1lID0gInRhcmdldF9uYW1lIikgJT4lCiAgbXV0YXRlKG5hbWUgPSBwYXN0ZTAoImciLCBzdGFydCwgIl8iLCByZWYsICI+IiwgYWx0KSkgJT4lCiAgZHBseXI6OnNlbGVjdCgKICAgIG5hbWUsIHN0YXJ0LCByZWYsIGFsdCwgcmVmLAogICAgdGFyZ2V0X25hbWUsIHBvc19wcm90ZWluLAogICAgcmVmX2NvZG9uLCB2YXJfY29kb24sIHJlZl9hYSwgZGlzdAogICkKYGBgCgpgYGB7cn0KdGFibGUoY29kaW5nX3N5biRkaXN0KQpgYGAKCmBgYHtyfQpjb2Rpbmdfc3luIDwtCiAgY29kaW5nX3N5biAlPiUKICBkcGx5cjo6c2VsZWN0KC1kaXN0KSAlPiUKICBncm91cF9ieShuYW1lKSAlPiUKICBtdXRhdGUodGFyZ2V0X25hbWUgPSBwYXN0ZSh0YXJnZXRfbmFtZSwgY29sbGFwc2UgPSAiOyIpKSAlPiUKICBkcGx5cjo6c2xpY2UoMSkKY29kaW5nX3N5bgpgYGAKCgpgYGB7cn0KIyMgUHJldmlvdXMgY29kZSBmb3IgaW5jbHVkaW5nIGludHJvbmljIHZhcmlhbnRzISEKCiMgdmFyaWFudHNfc252X2ludHJvbiA8LQojICAgdmFyaWFudHNfc252ICU+JQojICAgZmlsdGVyKGxvY2F0aW9uICVpbiUgYygiaW50cm9uIiwgInNwbGljZVNpdGUiKSkKCiMgbXV0X3Bvc19kaXN0IDwtIDMKIyBpbnRyb25fc3luIDwtCiMgICB2YXJpYW50c19zbnZfaW50cm9uICU+JQojICAgZHBseXI6OnNlbGVjdChuYW1lLCBzdGFydCwgcmVnaW9uX2xlbiwgcG9zX3JlZ2lvbikgJT4lCiMgICBtdXRhdGUocG9zX3JlZ2lvbl9jb21wID0gcmVnaW9uX2xlbiAtIHBvc19yZWdpb24pICU+JQojICAgbXV0YXRlKHVwc3RyZWFtID0gY2FzZV93aGVuKAojICAgICBwb3NfcmVnaW9uX2NvbXAgPCA4IH4gRiwKIyAgICAgcG9zX3JlZ2lvbl9jb21wID49IDggfiBUCiMgICApKSAlPiUKIyAgIG11dGF0ZSgKIyAgICAgc3RhcnRfc3luID0gaWZfZWxzZSh1cHN0cmVhbSwgc3RhcnQgKyBtdXRfcG9zX2Rpc3QsIHN0YXJ0IC0gbXV0X3Bvc19kaXN0KSwKIyAgICAgcmVmID0gbWFwX2NocigKIyAgICAgICBzdGFydF9zeW4sCiMgICAgICAgfiBhcy5jaGFyYWN0ZXIoc3Vic2VxKGhnX2dlbm9tZVtbImNocjciXV0sIC4sIC4pKQojICAgICApCiMgICApCiMKCiMgZHVwX2FsdGVybmF0aXZlcyA8LQojICAgaW50cm9uX3N5biAlPiUKIyAgIGZpbHRlcihzdGFydCAlaW4lIGludHJvbl9zeW4kc3RhcnRfc3luKSAlPiUKIyAgIHNlcGFyYXRlKG5hbWUsIGludG8gPSBjKCJlZGl0IiwgImFsdDAiKSwgcmVtb3ZlID0gRiwgc2VwID0gIj4iKSAlPiUKIyAgIHNlcGFyYXRlKGVkaXQsIGludG8gPSBjKCJsb2MiLCAicmVmMCIpLCByZW1vdmUgPSBGLCBzZXAgPSAiXyIpICU+JQojICAgZHBseXI6OnNlbGVjdChuYW1lLCBzdGFydCwgcmVmMCwgYWx0MCkgJT4lCiMgICBncm91cF9ieShzdGFydCkgJT4lCiMgICBtdXRhdGUoYmFzZXMgPSBwYXN0ZShhbHQwLCBjb2xsYXBzZSA9ICIsIikpICU+JQojICAgdW5ncm91cCgpICU+JQojICAgbXV0YXRlKGJhc2VzID0gcGFzdGUwKGJhc2VzLCAiLCIsIHJlZjApKSAlPiUKIyAgIHJvd3dpc2UoKSAlPiUKIyAgIG11dGF0ZShhbHRfMiA9IHNldGRpZmYoYygiQSIsICJDIiwgIlQiLCAiRyIpLAojICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfc3BsaXQoYmFzZXMsIHBhdHRlcm4gPSAiLCIpW1sxXV0pWzFdKSAlPiUKIyAgIG11dGF0ZShuYW1lX3N5bSA9IHBhc3RlMCgiZyIsIHN0YXJ0LCAiXyIsIHJlZjAsICI+IiwgYWx0XzIpKSAlPiUKIyAgIGRwbHlyOjpzZWxlY3QobmFtZSwgbmFtZV9zeW0sIGFsdF8yKQojIGR1cF9hbHRlcm5hdGl2ZXMKCiMgaW50cm9uX3N5biA8LQojICAgaW50cm9uX3N5biAlPiUKIyAgIG11dGF0ZShhbHQgPSBjYXNlX3doZW4oCiMgICAgIHJlZiA9PSAiRyIgfiAiQSIsCiMgICAgIHJlZiA9PSAiQSIgfiAiRyIsCiMgICAgIHJlZiA9PSAiQyIgfiAiVCIsCiMgICAgIHJlZiA9PSAiVCIgfiAiQyIKIyAgICkpICU+JQojICAgZHBseXI6OnNlbGVjdChuYW1lLCBzdGFydF9zeW4sIHJlZiwgYWx0KSAlPiUKIyAgIGRwbHlyOjpyZW5hbWUodGFyZ2V0X25hbWUgPSAibmFtZSIsIHN0YXJ0ID0gInN0YXJ0X3N5biIpICU+JQojICAgbXV0YXRlKG5hbWUgPSBwYXN0ZTAoImciLCBzdGFydCwgIl8iLCByZWYsICI+IiwgYWx0KSkgJT4lCiMgICBkcGx5cjo6c2VsZWN0KG5hbWUsIHN0YXJ0LCByZWYsIGFsdCwgdGFyZ2V0X25hbWUpICU+JQojICAgZ3JvdXBfYnkobmFtZSkgJT4lCiMgICBtdXRhdGUodGFyZ2V0X25hbWUgPSBwYXN0ZSh0YXJnZXRfbmFtZSwgY29sbGFwc2UgPSAiOyIpKSAlPiUKIyAgIGRwbHlyOjpzbGljZSgxKQoKCiMgaW50cm9uX3N5biA8LQojICAgbGVmdF9qb2luKGludHJvbl9zeW4sCiMgICAgIGR1cF9hbHRlcm5hdGl2ZXMsCiMgICAgIGJ5ID0gIm5hbWUiCiMgICApICU+JQojICAgbXV0YXRlKAojICAgICBuYW1lID0gaWZfZWxzZShpcy5uYShuYW1lX3N5bSksIG5hbWUsIG5hbWVfc3ltKSwKIyAgICAgYWx0ID0gaWZfZWxzZShpcy5uYShhbHRfMiksIGFsdCwgYWx0XzIpCiMgICApICU+JQojICAgZHBseXI6OnNlbGVjdCgtbmFtZV9zeW0sIC1hbHRfMikKCiMgc3luX3ZhcmlhbnRzIDwtCiMgICBiaW5kX3Jvd3MoCiMgICAgIGNvZGluZ19zeW4gJT4lCiMgICAgICAgbXV0YXRlKGxvY2F0aW9uID0gImNvZGluZyIpLAojICAgICBpbnRyb25fc3luICU+JQojICAgICAgIG11dGF0ZSgKIyAgICAgICAgIHBvc19wcm90ZWluID0gTkEsCiMgICAgICAgICByZWZfY29kb24gPSBOQSwKIyAgICAgICAgIHZhcl9jb2RvbiA9IE5BLAojICAgICAgICAgcmVmX2FhID0gTkEsCiMgICAgICAgICBsb2NhdGlvbiA9ICJpbnRyb24iCiMgICAgICAgKQojICAgKQojIHN5bl92YXJpYW50cwpgYGAKCgpgYGB7cn0Kc3luX3ZhcmlhbnRzIDwtCiAgbGVmdF9qb2luKAogICAgY29kaW5nX3N5biAlPiUKICAgICAgbXV0YXRlKGxvY2F0aW9uID0gImNvZGluZyIpLAogICAgdmFyaWFudHNfc252ICU+JQogICAgICBkcGx5cjo6c2VsZWN0KG5hbWUsIGlkKSwKICAgIGJ5ID0gIm5hbWUiCiAgKSAlPiUKICBtdXRhdGUoCiAgICBzeW5faW5fdGFyZ2V0ID0gbmFtZSAlaW4lIHZhcmlhbnRzX2R0JG5hbWUsCiAgICBudW1fdGFyZ2V0cyA9IHN0cl9jb3VudCh0YXJnZXRfbmFtZSwgIjsiKSArIDEKICApCnN5bl92YXJpYW50cwpgYGAKCmBgYHtyfQpzeW5fdGFyZ2V0X21hcCA8LQogIHN5bl92YXJpYW50cyAlPiUKICBncm91cF9ieShudW1fdGFyZ2V0cywgc3luX2luX3RhcmdldCkgJT4lCiAgdGFsbHkoKQpzeW5fdGFyZ2V0X21hcApgYGAKCgoKYGBge3J9CnN5bl92YXJpYW50c19sb25nIDwtCiAgc3luX3ZhcmlhbnRzICU+JQogIHNlcGFyYXRlX3Jvd3ModGFyZ2V0X25hbWUsIHNlcCA9ICI7IikgJT4lCiAgZHBseXI6OnNlbGVjdCgKICAgIHRhcmdldF9uYW1lLCBuYW1lLCBzdGFydCwgcmVmLAogICAgYWx0CiAgKSAlPiUKICBzZXRfbmFtZXMoYygKICAgICJuYW1lIiwgIm5hbWVfc3luIiwgInN0YXJ0X3N5biIsCiAgICAicmVmX3N5biIsICJhbHRfc3luIgogICkpCnN5bl92YXJpYW50c19sb25nCmBgYAoKCmBgYHtyfQp2YXJpYW50c19kdCA8LQogIGxlZnRfam9pbih2YXJpYW50c19kdCwgc3luX3ZhcmlhbnRzX2xvbmcsIGJ5ID0gIm5hbWUiKQp2YXJpYW50c19kdApgYGAKCmBgYHtyfQp2YXJpYW50c19kdCA8LQogIHZhcmlhbnRzX2R0ICU+JQogIG11dGF0ZSh0YXJnZXRfaW5fc3luID0gaWZfZWxzZShuYW1lICVpbiUgc3luX3ZhcmlhbnRzJG5hbWUsIFQsIEYpKSAlPiUKICBtdXRhdGUobmFtZV90YXJnZXRfc3luID0gcGFzdGUwKG5hbWUsICI6IiwgbmFtZV9zeW4pKSAlPiUKICBtdXRhdGUoCiAgICBjbGludmFyID0gaWZfZWxzZShncmVwbCgiXFxiXFxkK1xcYiIsIGlkKSwgVCwgRiksCiAgICBjb3NtaWMgPSBpZl9lbHNlKGdyZXBsKCJDT1NWIiwgaWQpLCBULCBGKSwKICAgIGJhc2VfZWRpdCA9IGlmX2Vsc2UoZ3JlcGwoImdcXGQrX1tBLVpdKz5bQS1aXSsiLCBpZCksIFQsIEYpCiAgKSAlPiUKICBkcGx5cjo6c2VsZWN0KAogICAgbmFtZSwgaWQsIHJlZiwgYWx0LCByZWZfYWEsIHZhcl9hYSwgcG9zX3Byb3RlaW4sCiAgICB0eXBlLCBjb25zZXF1ZW5jZSwgbG9jYXRpb24sIG5hbWVfc3luLCBuYW1lX3RhcmdldF9zeW4sCiAgICB0YXJnZXRfaW5fc3luLCBhbHRfZWZmZWN0LAogICAgY2xpbnZhciwgY29zbWljLCBiYXNlX2VkaXQsIHN0YXJ0LCBzdG9wLCBzdGFydF9zeW4sIGV2ZXJ5dGhpbmcoKQogICkgICU+JQogIG11dGF0ZShuYW1lX3RhcmdldF9zeW49aWZfZWxzZShpcy5uYShuYW1lX3N5biksIE5BLCBuYW1lX3RhcmdldF9zeW4pKSAKdmFyaWFudHNfZHQKYGBgCgoKCgojIyMgU3BsaXQgdmFyaWFudHMgaW50byB0YXJnZXQsIHRhcmdldF9zeW4sIGFuZCBzeW4KCgoKYGBge3J9CnZhcmlhbnRzX3NudiA8LQogIHZhcmlhbnRzX2R0ICU+JQogIGZpbHRlcighaXMubmEobmFtZV9zeW4pKSAgCgoKdGFyZ2V0X3N5bl92YXJpYW50cyA8LQogIHZhcmlhbnRzX3NudiAgJT4lCiAgZHBseXI6OnNlbGVjdChuYW1lX3RhcmdldF9zeW4sIG5hbWVfc3luLCBuYW1lKSAlPiUKICBzZXRfbmFtZXMoYygidGFyZ2V0X25hbWUiLCJuYW1lX3N5biIsICJuYW1lX3RhcmdldCIpKSAgJT4lCiAgbXV0YXRlKCBuYW1lX3RhcmdldF9zeW49TkEsCiAgICAgICAgICBudW1fdGFyZ2V0cz1OQSwKICAgICAgICAgIHBhaXJlZF90YXJnZXRzX2FzX3N5bj0gTkEsIAogICAgICAgICAgcGFpcmVkX3RhcmdldHNfc3luX2FzX3N5bj0gTkEpICU+JQogIGRwbHlyOjpzZWxlY3QodGFyZ2V0X25hbWUsIG5hbWVfdGFyZ2V0LCBuYW1lX3N5biwgCiAgICAgICAgICAgICAgICBuYW1lX3RhcmdldF9zeW4sCiAgICAgICAgICAgICAgICBudW1fdGFyZ2V0cywgcGFpcmVkX3RhcmdldHNfYXNfc3luLAogICAgICAgICAgICAgICAgcGFpcmVkX3RhcmdldHNfc3luX2FzX3N5biApCnRhcmdldF9zeW5fdmFyaWFudHMKCmBgYAoKYGBge3J9CnN5bl92YXJpYW50c19kdCA8LQogIHZhcmlhbnRzX3NudiAlPiUKICBkcGx5cjo6c2VsZWN0KG5hbWVfc3luLCBuYW1lLCBuYW1lX3RhcmdldF9zeW4pICU+JQogIHNldF9uYW1lcyhjKCJ0YXJnZXRfbmFtZSIsICJuYW1lX3RhcmdldCIsICJuYW1lX3RhcmdldF9zeW4iICkpICAlPiUKCiAgZ3JvdXBfYnkodGFyZ2V0X25hbWUpJT4lIAogIG11dGF0ZShuYW1lX3RhcmdldCA9IHBhc3RlKG5hbWVfdGFyZ2V0LCBjb2xsYXBzZSA9ICI7IiksCiAgICAgICAgIG5hbWVfdGFyZ2V0X3N5biA9IHBhc3RlKG5hbWVfdGFyZ2V0X3N5biwgY29sbGFwc2UgPSAiOyIpKSAlPiUgCiAgZHBseXI6OnNsaWNlKDEpICAgICU+JSAKICBtdXRhdGUoIAogICAgICAgICAgc3luX2luX3RhcmdldCA9IHRhcmdldF9uYW1lICVpbiUgdmFyaWFudHNfZHQkbmFtZSwKICAgICAgICAgIG51bV90YXJnZXRzID0gc3RyX2NvdW50KG5hbWVfdGFyZ2V0LCAiOyIpICsgMQogICkKCgpzeW5fdmFyaWFudHNfZHRfZmlsdGVyZWQgPC0KICBzeW5fdmFyaWFudHNfZHQgJT4lCiAgbXV0YXRlKHRhcmdldF9pbl9zeW49TkEsCiAgICAgICAgbmFtZV9zeW49TkEsCiAgICAgICAgcGFpcmVkX3RhcmdldHNfYXNfc3luPSBOQSwgCiAgICAgICAgcGFpcmVkX3RhcmdldHNfc3luX2FzX3N5bj0gTkEpICU+JQogIGZpbHRlcighKHN5bl9pbl90YXJnZXQpKSU+JQogIGRwbHlyOjpzZWxlY3QodGFyZ2V0X25hbWUsIG5hbWVfdGFyZ2V0LCBuYW1lX3N5biwKICAgICAgICAgICAgICAgIG5hbWVfdGFyZ2V0X3N5biwKICAgICAgICAgICAgICAgIG51bV90YXJnZXRzLCAKICAgICAgICAgICAgICAgIHBhaXJlZF90YXJnZXRzX2FzX3N5biwgCiAgICAgICAgICAgICAgICBwYWlyZWRfdGFyZ2V0c19zeW5fYXNfc3luICkKCnN5bl92YXJpYW50c19pbl90YXJnZXQgPC0KICAgIHN5bl92YXJpYW50c19kdCAlPiUKICBmaWx0ZXIoKHN5bl9pbl90YXJnZXQpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1zeW5faW5fdGFyZ2V0KSAlPiUKICByZW5hbWUobmFtZV90YXJnZXQ9InBhaXJlZF90YXJnZXRzX2FzX3N5biIsCiAgICAgICAgIG5hbWVfdGFyZ2V0X3N5bj0icGFpcmVkX3RhcmdldHNfc3luX2FzX3N5biIpCnN5bl92YXJpYW50c19kdF9maWx0ZXJlZApgYGAKCgoKYGBge3J9CnZhcmlhbnRzX2R0IDwtCiAgbGVmdF9qb2luKHZhcmlhbnRzX2R0LCAKICAgICAgICAgIHN5bl92YXJpYW50c19pbl90YXJnZXQgJT4lCiAgcmVuYW1lKHRhcmdldF9uYW1lPSJuYW1lIiksCiAgYnk9Im5hbWUiKQp2YXJpYW50c19kdApgYGAKCmBgYHtyfQp0YXJnZXRfdmFyaWFudHMgPC0KICB2YXJpYW50c19kdCAlPiUKICBkcGx5cjo6c2VsZWN0KG5hbWUsIG5hbWVfc3luLCBuYW1lX3RhcmdldF9zeW4sIHBhaXJlZF90YXJnZXRzX2FzX3N5biwgcGFpcmVkX3RhcmdldHNfc3luX2FzX3N5biwgbnVtX3RhcmdldHMpICU+JQogIHNldF9uYW1lcyhjKCJ0YXJnZXRfbmFtZSIsICJuYW1lX3N5biIsICJuYW1lX3RhcmdldF9zeW4iLCAicGFpcmVkX3RhcmdldHNfYXNfc3luIiwgInBhaXJlZF90YXJnZXRzX3N5bl9hc19zeW4iLCAibnVtX3RhcmdldHMiKSkgICU+JQogIG11dGF0ZShuYW1lX3RhcmdldD1OQSkgICU+JQogIGRwbHlyOjpzZWxlY3QodGFyZ2V0X25hbWUsIG5hbWVfdGFyZ2V0LCBuYW1lX3N5biwKICAgICAgICAgICAgICAgIG5hbWVfdGFyZ2V0X3N5biwKICAgICAgICAgICAgICAgIG51bV90YXJnZXRzLCAKICAgICAgICAgICAgICAgIHBhaXJlZF90YXJnZXRzX2FzX3N5biwgCiAgICAgICAgICAgICAgICBwYWlyZWRfdGFyZ2V0c19zeW5fYXNfc3luICkKICAKdGFyZ2V0X3ZhcmlhbnRzCmBgYAoKCmBgYHtyfQphbGxfdmFyaWFudHNfcGFpcmVkIDwtIAogIGJpbmRfcm93cyh0YXJnZXRfdmFyaWFudHMsIAogICAgICAgICAgICB0YXJnZXRfc3luX3ZhcmlhbnRzLCAKICAgICAgICAgICAgc3luX3ZhcmlhbnRzX2R0X2ZpbHRlcmVkKQphbGxfdmFyaWFudHNfcGFpcmVkIApgYGAKCgoKIyMjIFNhdmUgdG8gZmlsZXMKCmBgYHtyfQp3cml0ZV90c3YoCiAgYWxsX3ZhcmlhbnRzX3BhaXJlZCwKICBhbGxfdmFyaWFudHNfcGFpcmVkX3BhdGgKKQoKd3JpdGVfdHN2KAogIHZhcmlhbnRzX2R0LCB2YXJpYW50c190YWJsZV9wYXRoKQpgYGAKCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK